目录
一. this和super关键字
1. this关键字
2. super关键字
二. 重写
三. final关键字
四. 多态
五. 抽象类
1. 抽象方法
2. 抽象类
3. 面向抽象设计
一. this和super关键字
1. this关键字
this 当前对象的引用
this.属性 this.方法名() this() -- 调用构造函数 放在代码第一行
细节:
●可以用
this
来区分属性和局部变量。●在类的方法中,我们可以使用this.属性或this.方法的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略this.。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用this.变量的方式,表明此变量是属性,而非形参。
●使用this访问属性和方法时,如果在本类中未找到,会从父类中查找。调用属性和方法:
class Person{ // 定义Person类private String name ;private int age ;public Person(String name,int age){this.name = name ; this.age = age ; }public void getInfo(){System.out.println("姓名:" + name) ;this.speak();}public void speak(){System.out.println(“年龄:” + this.age);} }
调用构造方法:
●this(形参列表)必须声明在当前构造器的首行
class Person{ // 定义Person类private String name ;private int age ;public Person(){ // 无参构造器System.out.println("新对象实例化") ;}public Person(String name){this(); // 调用本类中的无参构造器this.name = name ;}public Person(String name,int age){this(name) ; // 调用有一个参数的构造器this.age = age;}public String getInfo(){return "姓名:" + name + ",年龄:" + age ;} }
2. super关键字
super 子类调用父类的内容
super 表示的是超类或者父类的意思
super.属性 调用父类的成员变量 super.方法名() 调用父类的成员方法 super() 调用父类的构造方法
使用:
可以在子类中显示地调用父类的结构。
构造方法里面:
●子类默认调用父类无参构造方法super()●如果父类没有无参构造,则需要手动使用super(参数)来调用父类的有参构造
●如果显示的写了super(参数),默认的则不赠送
●super()一定是在第一行
●this()必须写在第一行,所以super()和this()不能同时出现父类:
public class Person {protected String name;protected int age;public String getName() {return name;}public Person(String name, int age) {super();this.name = name;this.age = age;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
子类:
public class Student extends Person {private int score;public Student() {//默认调用父类无参构造方法// super();//调用父类的有参构造方法super("zkt",18);}}
二. 重写
在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为重写(Override)
语法规则:在子类和父类中有方法名完全一致,返回值类型相同的方法
●发生在子类和父类中,如果父类所提供的方法不能满足子类的需求,则子类可以重写
●方法名相同,参数项相同,返回值也相同,子类的修饰符>=父类的修饰符,方法体不同返回值:子类重写的方法的返回值范围可以小于父类的方法的返回值范围
父类:
class Person {public void run() {System.out.println("Person.run");} }
子类: 在子类Student中,重写这个run()方法
class Student extends Person {@Overridepublic void run() {System.out.println("Student.run");} }
手动重写Object类的方法:
在Java中,所有的class类最终都继承自Object,而Object定义了几个重要的方法
@Overridepublic String toString() {return "姓名" + name + "身份证号:" + cardId;}// equals 只能用在引用数据类型上// object中的equals方法比较的是两个对象的地址是否相同,String类比较的是内容是否相同(因为其重写了equals方法)// 如果自己想要看内容是否相同 重写equals方法@Overridepublic boolean equals(Object obj) {// 1.先比较地址是否相同if (this == obj) {return true;}// 2.先判断是否是Person类型if (obj instanceof Person) {// 向下转型Person p1 = (Person) obj;return this.name.equals(p1.name) && this.cardId.equals(p1.cardId);}return false;}// 地址改成了属性的地址和// 如果两个对象的属性完全相同 则hashCode值也完全相同@Overridepublic int hashCode() {return name.hashCode()+cardId.hashCode();}
重载:
●方法的重载:在同一个类中,方法名相同,参数项不同(类型,个数,顺序)
●和返回值无关,发生在编译期
区别:
N 区别 重载 重写 1 概念 方法名称相同,参数的类型及个数不同 方法名称、返回值类型、参数的类型及个数完全相同 2 范围 一个类 继承关系 3 限制 没有权限要求 被重写的方法不能拥有比父类更严格的访问控制权限
三. final关键字
继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。
父类:
public class Fu {public final int AGE = 18;public final int[] AAA = { 12, 2, 23, 45 };public final void eat() {System.out.println("这个是父类的eat方法");} }
1.1:final用来修饰字段基本数据类型,常量-值不可变
//1.1:final用来修饰字段基本数据类型,常量-值不可变Fu fu1 =new Fu(); // fu1.AGE=10;System.out.println(fu1.AGE);//18
1.2:final用来修饰字段(引用数据类型)地址不可发生变化,值可以变
fu1.AAA[0]=1000;System.out.println(Arrays.toString(fu1.AAA));//[1000, 2, 23, 45]
2.final用来修饰方法,此方法不能重写,此方法可以被子类调用
//2.final用来修饰方法,此方法不能重写,此方法可以被子类调用Zi zi = new Zi();zi.eat();//这个是父类的eat方法
class Zi extends Fu{// compile error: 不允许覆写@Overridepublic void eat() {System.out.println("这个是子类的eat方法");} }
3.fianl用来修饰类,父类不能被继承,太监类
四. 多态
多态指的是同一对象,在不同时刻表现出来的多种形态
多态实现的三要素:
●有继承关系/实现关系
●有方法的重写
●有父类的引用指向子类,向上转型
示例:
Shape类:
public class Shape {public void draw() {} }
子类:
class Circle extends Shape {@Overridepublic void draw() {System.out.println("⭕");} } class Flower extends Shape {@Overridepublic void draw() {System.out.println("❀");} } class Star extends Shape {@Overridepublic void draw() {System.out.println("⭐");} } class Triangle extends Shape {@Overridepublic void draw() {System.out.println("▲");} } class Square extends Shape {@Overridepublic void draw() {System.out.println("■");} }
不使用多态写法:
public static void main(String[] args) {Flower flower = new Flower();Star star = new Star();Circle circle = new Circle();Triangle triangle = new Triangle();Square square = new Square();String[] shapeStrings = { "flower", "star", "circle", "triangle", "square" };// 不使用多态绘制图形for (int i = 0; i < shapeStrings.length; i++) {if ("flower".equals(shapeStrings[i])) {flower.draw();} else if ("star".equals(shapeStrings[i])) {star.draw();} else if ("circle".equals(shapeStrings[i])) {circle.draw();} else if ("triangle".equals(shapeStrings[i])) {triangle.draw();} else if ("square".equals(shapeStrings[i])) {square.draw();}}}
多态写法:
public static void main(String[] args) {Shape[] shapes = {new Flower(),new Star(),new Triangle(),new Square()};for (Shape shape : shapes) {shape.draw();}}
多态的写法优点:
●类的调用者对类的使用成本进一步降低,多态是让类的调用者不用知道类的具体类型.
●可以降低圆圈复杂度
●可拓展性增强多态的写法:
父类 对象名= new 子类() #父类类型指向子类对象 eg: Fu fu = new Zi() 接口 对象名= new 实现类() #接口类型指向实现类对象
多态中的成员访问特点:见java基础09
●成员变量的访问特点:编译看左边,运行看左边,如果没有则向上查找。
●成员方法的访问特点: 编译看左边,运行看右边,如果没有则向上查找。
多态的优缺点:
●优点:父类类型/接口类型作为方法的参数/返回值,提高了程序的扩展性
●缺点:无法访问子类/实现类中独有的方法。(需要向下转型)
向上下转型:见java基础09
五. 抽象类
●当一个类被abstract修饰这个类就是抽象类
●在Java中,—个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
1. 抽象方法
抽象方法:
●抽象方法没有方法体
●抽象方法使用abstract关键字来修饰,修饰符和返回值中间
●抽象方法必须写在抽象类中
●抽象方法的修饰符不能是privatepublic abstract class Shape {// 定义了一个"规范"public abstract void draw(); }
2. 抽象类
抽象类:
●抽象类使用abstract关键字来修饰,放在修饰符和class中间
●子类必须要重写抽象类中的抽象方法,除非子类也是抽象类
●抽象类无法实例化对象
●抽象类中成员变量,常量,构造方法(存在的意义,初始化成员变量)public abstract class Shape {public int age;public final double PI = 3.14;public Shape() {this.age = 18;System.out.println("这个是父类的无参构造方法");}// 定义了一个"规范"public abstract void draw();public void doSth() {System.out.println("这个是shape的doSth方法");} }
●子类是抽象类,可以不用实现抽象方法,当然也可以实现抽象方法(如果在此处可以完成)
//子类是抽象类,可以不用实现抽象方法,当然也可以实现抽象方法(如果在此处可以完成) abstract class Circle extends Shape {}
●子类是普通类,必须要重写父类中的抽象方法
//子类是普通类,必须要重写父类中的抽象方法 class Flower extends Shape {public Flower() {super();}@Overridepublic void draw() {System.out.println("❀");} }
●抽象类不能实例化对象
报错
Circle c1 =new Circle();//抽象类不能实例化对象Shape s1 = new Shape();
子类调用:
Flower f1 = new Flower();System.out.println(f1.age);f1.doSth();
多态写法:
Shape s1 = new Flower();//多态写法s1.doSth();s1.draw();
3. 面向抽象设计
面向抽象设计的本质是:
●上层代码只定义规范(例如:abstract class Person)
●不需要子类就可以实现业务逻辑(正常编译)
●具体的业务逻辑由不同的子类实现,调用者并不关心public abstract class Person {protected String name;public Person(String name) {super();this.name = name;}// 定义了规范public abstract void run(); } class Student extends Person {public Student(String name) {super(name);}@Overridepublic void run() {System.out.println("学生类"+name+"的run方法");}} class Teacher extends Person{public Teacher(String name) {super(name);}@Overridepublic void run() {System.out.println("老师类"+name+"的run方法");}}
这种引用抽象类的好处在于,我们对其进行方法调用,并不关心Person类型变量的具体子类型:
Person[] persons = { new Student("zkt1"), new Student("zkt2"), new Teacher("zkt3") };for (Person person : persons) {//在运行的过程中,不必过多关注子类的业务实现,也不必关注子类的具体类型person.run();}