第五章 继承,多态
第五章 继承,多态
一、继承性(extend)
二、方法的重写(overwrite/override)
三、四种权限修饰符(主要说明)protected)
四、super关键字
五、多态性
六、Object类的使用
七、==和equals()的区别
八、toString()
九、单元测试方法 包装类
一、继承性(extend)
有一个person类,要新建一个student类,其中student一些属性、方法和方法person里是一样的,这个时候就可以考虑继承,就会获得父类的属性和方法
public class Student extends Person{ // 写下自己没有定义,person有的student都有,构造器自己写 }
减少代码冗余,提高代码重用性;促进功能扩展;多态化的前提
class A extends B {}
A:子类衍生、subclass
B:超类、基类
1.父类声明为private子类继承父类后,仍然认为父类的私有结构已经获得。由于封装的影响,子类不能直接调用父类的结构
2.继承父类后,子类还可以声明其独特的属性和方法,实现功能的扩展。
3.java继承的规定:
一个类可以由多个子类继承
java中类单继承:一个类只能有一个父亲
子父是一个相对的概念:多层继承
子类直接继承的父类称为直接父类,间接继承称为间接父类
子类继承父类吼,获得直接父类和所有间接父类包含的属性和方法
4.如果父类没有明确声明,则继承于此类java.lang.Object类
所有的java类(除了他自己)直接或间接继承java.lang.Object
二、重写方法(overwrite/override)
1.子类可以根据需要改变从父类继承的方法。在实施过程中,子类的方法将覆盖父类的方法
2.区分重载和重写:
重载:对于具有相同返回类型和名称的方法,形参不同,构成方法之间的重载(两个相同)
重写:子类根据自己的需要重写继承的父类的方法,要求方法的返回类型、名称和形参相同
3.重写规定
方法的声明 权限修饰符 返回值类型 方法名(形参列表)throws 异常的类型{
//方法体
}
俗称:子类称重写法 父类被称为被重写的方法
①子类重写的方法名、形参类型和父类重写的方法名he形状参数表相同
② 权限修饰符:子类重写法的权限修饰符不小于父类重写法的权限修饰符
特殊:子类不能重写父类private方法
③返回值类型:
父类重写方法的返回值类型是void,子类重写法的返回值类型也是如此void
如果父类重写法的返回值类型是其他返回值类型,子类重写法可以是父类返回值类型或类型的子类(object和String)
父类重写方法的返回值类型为基本数据类型(如:double),子类重写法的返回值类型必须相同(如double)
④子类重写法抛出的异常类型不大于父类重写法抛出的异常类型
子类和父类同名参数的方法 要么都是非static(考虑重写)static(不是重写)
三、四种权限修饰符(主要说明)protected)
这里主要说四种不同的权限修改protected,可以看到不同包中的子类
四、super关键字
在我在子类中重写了一种方法后,我想用父类中重写的方法(生病了吗?
1.super理解为:父类
2.super可用于调用属性、方法、构造器
// 自己的ID 1001 System.out.println(id); // 父类的ID 1002 System.out.println(super.id);
3.可在子类方法或构造器中使用super.属性”或“super.方法”显示调用父类中声明的属性或方法。但是通常情况下会省略"super."
特殊情况:当同名属性在子类和父类中定义时,我们希望在子类中调用父类声明的属性,必须显示super.属性的方法表明调用了父性属性
4.方法:我在子类中重写了一种方法后,又想用父类中重写的方法,super.方法”
// 自己的eat 学生多吃营养丰富的食物 this.eat(); // 父类的eat 吃饭 super.eat();
5.构造器
①我们可以在子类 构造器中显式使用super(形参类声明的指定结构器(形参列表)
public Student (String name, int age,String major){ suer(name, age);//这个是父类里面的构造器
this.major = major;
}
④在构造器的首行没有显式的声明“super(形参列表)”或“this(形参列表)”,则默认使用super()构造器
⑤在类的多个构造器中,至少有一个类的构造器中使用了“super(形参列表)”,调用父类中的构造器
五、多态性
可以理解为一个事物的多种形态
1.Person p2 = new Man();//Person是Man的父类
p2.eat() 执行的是Man子类的eat方法
就好比队列的定义: Queue que = new LinkedList();
多态的使用:当调用子父类中时,实际执行的是子类重写父类的方法---虚拟方法调用 即父类可以用子类中重写的方法
但是注意,p2能调的只有Person里的方法,即编译时是编译左边声明的类型,但是执行的时候是执行 Man里面的
3.多态的使用:虚拟方法的调用
有了对象的多态性后,我们在编译期,只能调用父类中声明的方法,在运行期,我们实际执行 的是子类重写的父类的方法
编译,看左边;运行,看右边
4.多态性使用前提:① 要有类的继承关系②方法的重写
(
public static void main(String[] args) {
AnimalTest test = new AnimalTest();
// 如果没有多态性,即使要执行相同的操作,也要写一个新的方法改变形参。
// 因此多态性可以省去重载方法
test.func(new Dog());//输出meat和dog
}
// 如果没有多态性,即使要执行相同的操作,也要写一个新的方法改变形参。
// 因此多态性可以省去重载方法
public void func(Animal animal){ //Animal animal = new Dog();
animal.eat();
animal.shout();
}
}
class Animal{
public void eat(){
System.out.println("eat");
}
public void shout(){
System.out.println("shout");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("meat");
}
public void shout(){
System.out.println("wang");
}
}
6.关于属性:对象的多态性只适用于方法 ,不适用于属性,左边定义的是谁,就是谁的属性
重载不表现为多态性
重写表现为多态性
7.instanceof
有了对象的多态性后,内存中实际上是加载了子类特有的的属性和方法的,但由于声明为父类类型,导致编译时只能调用父类中声明是属性和方法,子类特有的属性和方法不能调用。
如何调用子类特有的属性和方法?(要把对象改成子类的类型)将person类转为man类
Man m1 = (Man)p2;即(但这么写可能有风险) 下面讲instanceof
使用强转时可能出现ClassCastException异常
instanceof: 使用方法 : a instanceof A判断对象a是否是类A的实例,boolean类型
使用情景:用于向下转型前的判断
如果 a instanceof A 返回TRUE,则 a instanceof B,其中类B是类A的父类
==:对于引用数据类型,是比较两个引用数据类型变量的地址值是否相同
子类重写了父类方法以后,系统不能把父类里的方法转移到子类,但是对于实例变量,子类有和父类同名的实例变量也不可能覆盖父类里定义的实例变量
六、Object类的使用
1.是所有java类的根父类,没有显式声明extends谁的话,就默认是Object。
2.Object类中的功能(属性、方法)
3.Object只声明了一个空参构造器
七、==和equals()的区别
1.==的使用,
==:运算符,用于基本数据类型变量和引用数据类型变量
基本数据类型变量:比较数值(除了Boolean,其他的不计较类型,只比较数值)。不同数据类型比,int i= 10; double j= 10.0; i== j true
char k= 10; i==k true
引用数据类型变量:比较两个对象的地址值是否相同,及两个引用是否指向同一个实体。
2.equals()方法的使用
是一个方法,而非运算符
通过对象.equals()调用,因此无法用于基础数据类型,只能用于引用数据类型
Object类中equals的定义的方法和==的作用是相同的:比较两个对象的地址值是否相同
但是有一些引用变量类型数据,他们的equals是重写过的如:等都引用数据类型变量了Object()
中的equals, 比较两个象的“实体内容”是否相同(属性)
通常情况下,自定义的类如果使用equals()的话,可以对其进行重写以实现对于两个对象的实体内容是否相同
equals()可以自动生成,跟get(),set()一样
八、toString()
引用数据类型变量.toString() 输出的是地址值,及当我们输出一个对象的引用时,调用的是object类中的toString()方法
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
都重写了toString()。使得在调用对象的toString()方法是,返回“实体内容”的信息(想返回啥你自己写)
九、单元测试方法 包装类
:可以针对某一段代码进行测试
步骤: 1.build path->add libraries -> JUnit4
2.创建一个Java类进行单元测试。此时的Java类要求:类是公共的;提供一个公共的无参构造器;
3.在此类中声明单元测试方法:此时的单元测试方法:方法的权限是public,没有返回值,没有形参
4.此单元测试方法上需要声明注解:@Test并在单元测试类中导入对应的包:import org.junit.Test
5。声明好单元测试方法以后们就可以在方法体内测试相关代码
6.写完代码后,左键双击单元测试方法名,右键 run as -JUnit Test
说明:执行结果没有任何异常,绿条 否则是红条
面向对象都是针对类来说的,但是基本数据类型并不具备类的特点和功能,所以针对每个基本数据类型,都给他们设计了一个类把他们包起来了
基本数据类型,包装类,string之间的相互转换
1.基本数据类型->包装
2.包装类->基本数据类型
调用包装类XXX的XXXValue()
补充:自动装箱和自动拆箱(不需要用构造器构造包装类了)
int num1 = 10;
Integer in2 = num1;
int num3 = in2;
3.基本数据类型、包装类--->String类型 valueOf
int num = 10;
//方式一:连接运算
String str1 = nums1 + "";
//方式二: 调用String的valueOf(XXX)
float f1 = 12.3f;
String str2 = String.valueOf(f1);//"12.3"
Double d1 = new Double(12.4);
String str3 = String.valueOf(d1);//"12.4"
4.String类型-->基本数据类型包装类 parseXXX
float f1 = 12.3f;
String str2 = Float.parseFloat(f1);//"12.3"
//注意此时的boolean类型有些特殊;
String str2 = "true1";
boolean b1 = Boolean.parseBoolean(str2);
//此时就会报错,布尔类型会严格检查是不是true 或 false,但是不区分大小写
注:对于三元运算符 X? A:B 一般要求A,和B是相同类型,如果类型不同会进行类型提升
Integer内部定义了Integer cache,保存-128~127范围整数,使用自动装箱方式给Integer赋值,在上面这个范围内的可以直接用cache里的数,不需要再new,提高效率