一、继承
1.1继承基础知识
使用关键字extend继承,子类可以继承父类的非私有成员,提高代码的复用性。
语法格式:
java">public class 子类 extends 父类{}
设置父类:
java">public class People {private String name;private int age;private char gender;public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public void setGender(char gender) {this.gender = gender;}public String getName() {return name;}public int getAge() {return age;}public char getGender() {return gender;}
}
设置子类
java">package jmy.oop_plus;public class Teacher extends People{private String skill;public String getSkill() {return skill;}public void setSkill(String skill) {this.skill = skill;}}
java">public class Test {public static void main(String[] args) {//1.创建对象,封装老师数据Teacher t1 = new Teacher();t1.setName("李老师");t1.setAge(28);t1.setGender('男');t1.setSkill("教语文");}
}
1.2 权限修饰符
权限修饰符的作用:限制类中的成员(成员变量、成员方法、构造器)能被访问的范围
private:只能在本类中
缺省:只能在本类、同一个包中的类
protected:只能在本类、同一个包中的类、以及子孙类
public:任意位置
一般来说,成员变量的属性一遍private,方法public(get和set)
1.3 继承的特点
单继承:子类只有一个父类。因为多继承会导致方法重名冲突
多层继承:孙子继承自父亲,父亲继承自爷爷
祖宗类:java中所有类的祖宗类是Object类。一个类要么直接继承Object,要么间接继承Object
继承后子类访问成员的特点:就近原则:先在子类局部范围找,再在子类成员范围找,然后再父类成员中找,如果父类范围没找到,就报错
如果子父类中出现了重名变量,会优先访问子类中的变量,但如果此时一定要访问父类的变量怎么办?使用super
java">public class Test {public static void main(String[] args) {A a = new A();B b = new B();b.show();//就近原则,先在子类的范围里找name}
}class A {String name = "这是父类的名字";
} //tips:java文件中,可以允许有多个类,但是public的只能有一个,这个公共的类作为文件名,这是龟腚class B extends A {String name = "这是子类的名字";public void show(){String name = "这是show的name";System.out.println(name);System.out.println(this.name);//this.name访问的子类这个对象System.out.println(super.name);//super 代表父类}
}
1.4方法重写
当子类觉得父类中某个方法不好用,无法满足需求的时候,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的方法,即方法重写
在重写一个方法的时候,在上面使用 :“@override”来作为标志,提醒一下。
重写的几个注意点:
1.子类重写父类的方法时,范围必须大于等于父类方法的权限(public > protected>缺省 )
2.重写方法的返回值类型,必须等于或者小于被重现的方法返回值类型
3.静态方法(因为静态的,属于类自己的东西,所以不能重写),私有方法(因为私有的,子类不能继承)不能重写,否则会报错
一个准则:声明不变(直接抄父类的定义),重新实现(方法的功能重新写)
java">public class Test {public static void main(String[] args) {cat c = new cat();c.cry();}
}class Animals{public void cry(){System.out.println("Cry!");}
}class cat extends Animals{@Override //方法重写的一个注解(标志)作为提醒:方法名称和形参列表必须和被重写方法一致,否则报错public void cry(){System.out.println("喵喵");//这就是override了}
}
方法重写的常见应用场景
1.子类重写父类的tostring方法,以便返回对象的内容
java"> @Override //toString方法是祖宗类object提供的一个方法,它返回的是一个hashcode,我们需要返回字符串,以便查看public String toString() { //重写toString方法,以便打印对象return "这是一只猫";}
1.5子类构造器的特点
子类的全部构造器,都会先调用父类的构造器,再执行自己的。
super()调用父类的构造器
因为:
默认情况下,子类的第一行都会有super(),写不写都会有,他会调用父类的无参构造器。
如果父类没有无参构造器,必须手写super()出来,去调用父类的有参构造器
java">public class Test {public static void main(String[] args) {Son s = new Son();//子类的构造器,必须先调用父类的构造器(有参或无参),再调用自己的}}
class Father{private Father(){System.out.println("这是父类的构造器");}public Father(int a){System.out.println("这是父类的有参构造器");}
}
class Son extends Father{public Son(){super(666);//使用super,指定调用父类的有参构造器System.out.println("这是子类的构造器");}
}
子类调用父类构造器的作用:
调用父类的有参构造器,把子类继承自属于父类这部分的数据完成初始化赋值
java">public class People {private String name;private int age;private char gender;public People() {}public People(String name, int age, char gender) {this.name = name;this.age = age;this.gender = gender;}
java">public class Teacher extends People{private String skill;public Teacher(String name, int age, char gender, String skill) {super(name,age,gender);//调用父类的有参构造器,把子类继承自父类的数据完成初始化赋值,name,age,gender实际上还是父类的属性//需要通过父类的构造器来初始化赋值this.skill = skill;}public String getSkill() {return skill;}public void setSkill(String skill) {this.skill = skill;}
1.6 this(...)调用兄弟构造器
java">public class test2 {public static void main(String[] args) {//使用this(...)去调用兄弟构造器Son s2 = new Son("张三",'男');//需求:当不传入age值时,默认输出18,此时需要用this调用兄弟构造器System.out.print(s2);}
}
java"> public Son(String name,char sex){this(name,18,sex); //this调用兄弟构造器,并把18传进去,作为默认值//以后,创建类的实例时,若不传age值,就默认为18}
java"> public Son(String name , int age , char sex){this.name = name;this.age = age;this.sex = sex;}@Overridepublic String toString() {return "名字: " + name + "年龄 " + age + "性别 " + sex;}
二、多态
2.1 认识多态
多态是在继承、实现下的一种现象,表现为行为多态、对象多态
多态的前提:有继承、实现关系,存在父类引用对象,存在方法重写
java">public class test {public static void main(String[] args) {//1.对象多态,行为多态animal a1 = new wolf();a1.run();System.out.println(a1.name);//输出:动物。 因为对于成员变量:编译、运行都是看左边。// 即看a1的左边,是animal,输出的是animal的nameanimal a2 = new tortoise();a2.run(); // 对于方法:编译看左边,运行看右边//tips:变量不强调多态性,都是看左边。方法才要看子类的具体情况}
}
java">public class wolf extends animal {String name = "狼";@Overridepublic void run(){System.out.println("wolf runs fast");}
2.2 多态的好处
1.在多态的情况下,右边的对象是解耦合的,方便扩展和维护。
java">People p1 = new teacher();
p1.run();
2.在定义方法时,使用父类类型的形参,可以接受一切子类对象,扩展性更强,更便利
java"> //2.多态的好处wolf w = new wolf();tortoise t = new tortoise();go(w);go(t);}//需求:开发一个游戏,让所有动物都跑起来public static void go(animal all_animals) { // 使用父类类型的变量作为参数,可以接受一切子类变量System.out.println("开始===========");all_animals.run();}
2.3多态的一个问题
多态下,调用不了子类的独有功能
java"> //多态的一个问题animal a3 = new wolf();//a3.eatSheep(); 报错,因为编译看左边,animal里并没有eatSheep这个方法w.eatSheep(); // 想调用子类的方法,必须使用子类对象调用
2.4多态下的类型转换
自动类型转换:子类变量给到父类对象
java">父类 变量名 = new 子类();
强制类型转换:
java">子类 变量名 = (子类) 父类变量
强转的时候,要小心,不能把乌龟转成狼/
强转前,可用 instanceof 关键字判断对象的真实类型,再做转换。