1 继承
今天来讲类与类之间的关系,前面我们封装了一个猫类,当我们封装一个狗类、鸟类,我们就会发现,在有些属性相同的情况下,get和set有重复,所以我们就会想到要抽离这些重复的代码,我们把这些重复的代码,抽出来,重新定义了一个动物类,这个类拥有了猫类、狗类、鸟类的通用特征,这个动物类就是父类,猫类狗类鸟类就是子类
我们让子类继承父类,拥有父类的特征,在java中,Object类是所有类的顶级父类,而且继承都是单根继承,一个类只能有一个父亲
我们在类名那里,写出继承的代码格式
public class Cat extends Animal{
}
在有继承关系的类中,我们在进行方法调用的时候,会先在自己的类中找有没有这个方法,有就用,没有就向上找父类的方法
如果父类与子类都有相同的方法,想要调用父类的方法的时候,可以使用super调用
如果处在同一条继承链上,他可以调用自己父类和父类以上的类的公共方法
@Override
public String toString() {
return super.toString()+
", type='" + type + '\'' +
'}';
}
2 super
super可以对父类的变量进行调用,但是要注意访问权限修饰符
super();调用父类的构造方法
super();必须放在构造方法的第一句
无参构造方法中,默认有依据super
super可以调用父类的 非私有的方法 和 全局变量
3 向上转型
子类转成父类,称之为向上转型,向上转型,子类对父类隐藏自己的功能
也就是说,当我们用父类的类型来接受子类对象的时候,我们的父类里面本身是没有这个方法的,我们这个父类对象就只能使用父类的方法,但是由于接受的是子类的对象,我们子类的功能还是在,但是被隐藏了
赋值的向上转型
Animal cat = new Cat();
cat.setName("胖熊");
cat.setAge(1);
((Cat) cat).setType("英短");
传参的向上转型
public static void main(String[] args) {
Animal cat = new Cat();
test(cat);
Animal dog = new Dog();
test(dog);
}
public static void test(Animal cat){
System.out.println(cat);
}
输出:
Cat{name='null', age=0, type='null'}
Dog{name='null', age=0, height='null'}
动态绑定: 程序会识别当前数据类型的变量中存放对象的实际类型,并且找到实际类型,执行实际类型中的方法
4 方法重写
子类拥有父类中的方法,但是方法体需要根据自己的类的特征重新书写,就是方法重写 @Override
规则:
1、必须在有继承关系的类之间
2、方法名、参数列表、返回值 都必须相同
3、访问权限的修饰符,子类必须大于等于父类
前面介绍到的toString 方法就是在进行方法重写,我们可以比较一下父子类
@Override
//父类
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
//子类
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
", type='" + type + '\'' +
'}';
}
我们在Animal Cat Dog 再创建一个类叫move类,如果是在以下例子执行的话:
//动物类
public void move(){
System.out.println("动物可以跑");
}
//猫类
public void move(){
System.out.println("胖熊往返跑");
}
//狗类
public void move(){
System.out.println("狗狗跑很快");
}
public class Test01 {
public static void main(String[] args) {
Animal animal = new Animal();
animal.move();
Animal cat = new Cat();
cat.move();
Animal dog = new Dog();
dog.move();
Test(cat);
Test(dog);
}
public static void Test(Animal cat){
cat.move();
}
}
我们就会发现,其实父类的方法体可以省略,反正子类会重写,但是在java中,我们父类的方法体省略,方法声明还是要有
如果一个方法只有方法声明的话,就是 抽象方法
抽象方法的书写格式 就是在返回值前面加 abstract 的关键词
public abstract class Animal {
private String name;
private int age ;
public abstract void move();
}
}
5 抽象类
抽象方法一定要在抽象类中
抽象类不一定有抽象方法
抽象类不能创造对象,因为创造对象的话,就要调用方法执行方法体,但是抽象方法中,没有方法体
抽象类中可以有:
属性、setget方法、构造方法、静态代码块、代码块、抽象方法
抽象类的实现可以通过匿名内部类
匿名内部类可以实现多个抽象方法
public class Test01 {
public static void main(String[] args) {
Animal animal = new Animal() {
@Override
public void run() {
System.out.println("匿名内部类的animal做的方法实现");
}
@Override
void eat() {
}
};
animal.run();
animal.eat();
}
}
一个类继承了抽象类,报错的解决方式:
1、重写抽象类中的方法
2、把自己声明为抽象类
6 访问权限修饰符
不同包下的类之间 | 不同包下的有继承关系的类中 | 同一包下的类之间 | 当前类 | |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | |
默认 | √ | √ | ||
private | √ |
测试代码如下:
A和Test01是一个包
B和Test02是一个包
public class Test01 {
public static void main(String[] args) {
//同个包下的类
A a = new A();
a.name="a";//public
a.number;//private
a.nature = "nature";//默认
a.age = 1;//protected
}
}
public class A {
public String name;
private int number ;
String nature ;
protected int age;
//当前类
public void test(){
System.out.println(name);
System.out.println(number);
System.out.println(nature);
System.out.println(age);
}
}
public class Test02 {
public static void main(String[] args) {
//不同包下的类
A a = new A();
a.name="a";//public
a.number;//private
a.nature = "nature";//默认
a.age = 1;//protected
}
}
public class B extends A {
public String name;
private int number ;
String nature ;
protected int age;
//不同包下有继承关系的类中
public void test(){
System.out.println(super.name);
System.out.println(super.number);
System.out.println(super.nature);
System.out.println(super.age);
}
}
前面提到,子类继承父类,方法重写的时候,子类的修饰符必须大于等于父类
子\父 | private | 默认 | protected | public |
---|---|---|---|---|
private | √ | |||
默认 | √ | √ | ||
proetected | √ | √ | √ | |
public | √ | √ | √ | √ |
private < 默认 < protected < public
抽象方法修饰符不可以使用private
7 向下转型
我们的向下转型,就是强制父类拥有子类的特征,我们不能在这里进行强制转换,因为这个会显示一个强制转换异常
想要避免这异常,我们可以先进行判断,再来转换
(对象 instanceof 类型) 是 true 不是 false
public class Test01 {
public static void main(String[] args) {
//创建一个家用电器对象
Appliances a = new Appliances();
//这个家用电器是不是冰箱
if (a instanceof Refrigerator){
//是 强转为冰箱
Refrigerator r = (Refrigerator)a;
}else {
//不是 转不了
System.out.println("类型不匹配,不可转换");
}
}
}
如果非要向下转型,必须建立在向上转型的基础上
下面考虑到test方法中的else返回字符串,则将接受类型从电器类型Appliances改为它和String的父类,Object
public class Test01 {
public static void main(String[] args) {
//这里使得它返回一个电冰箱对象被Object类接受 向上转型
Object a = test(0);
//a这个对象是电视类吗
if (a instanceof Television){
//是 向下转型 将a强转为电视类型
Television t = (Television)a;
//a这个对象是电冰箱类吗
}else if (a instanceof Refrigerator){
//是 向下转型 将a强转为电冰箱类型
Refrigerator r =(Refrigerator)a;
}else {
//都不是 类型不匹配
System.out.println("类型不匹配");
}
}
public static Object test(int num){
if (num == 0){
//如果是0 那就返回一个电视对象
return new Television();
}else if(num == 1) {
//如果不是0 那就返回一个电冰箱对象
return new Refrigerator();
}else{
return "没有匹配"
}
}
}