面向对象进阶
Static
静态变量
所有对象一起共享,就用static修饰
不属于对象,属于类的 可以用 类名.静态变量 = “”;赋值
但是 对象.静态变量也可以访问到内容
Static内存图
Student这个类的字节码文件加载到方法区,并在内存中创建了一个单独存放静态变量的空间,叫做静态区(JDK8之前是在方法区里的,之后就在堆内存中)。
静态区存放所有的静态变量。
此时,堆内存中还没有对象,因为没有new关键字出现。
所以,静态变量是随着类的加载而加载的,优先于对象出现的
对象空间里则存储所有非静态的成员变量。
静态方法
Javabean类 测试类 工具类
为什么要私有化?
为了不让创建对象,创建出来的对象没有意义,所以直接设为private
package exercise;import java.util.StringJoiner;public class ArrayUtil {private ArrayUtil() {}public static String printArr(int[] arr) {StringJoiner sj = new StringJoiner(", ", "[", "]");for (int i = 0; i < arr.length; i++) {sj.add(arr[i] + "");}return sj.toString();}public static double getAverage(double[] arr) {double sum = 0;for (int i = 0; i < arr.length; i++) {sum += arr[i];}return sum / arr.length;}}
public static int getMaxAge(ArrayList<Student> arrayList) {int maxAge = arrayList.get(0).getAge();for (int i = 1; i < arrayList.size(); i++) {int age = arrayList.get(i).getAge();maxAge = maxAge > age ? maxAge : age;}return maxAge;}
静态方法中没有this
因为,静态方法中一般都是对象共享的,与某个对象是没有关系的
this表示当前方法调用者的地址值,而静态方法不能被对象调用(只能被类调用),所以静态方法中就不存在this
而非静态方法中,方法是通过对象来调用的,所以在方法的形参中会有一个隐藏的this来表示当前调用者的地址值,通常都会省略这个this不写。
静态中用this会报错,不知道是调用的谁的name
Main方法
继承
父类 子类
什么时候用?
继承特点
如果一个父类中的方法中使用了private,则子类就不能访问这个方法,只有在本类中才能用
所以,子类只能访问父类中非私有的成员
构造方法不能继承
成员变量都能继承,但是子类不能直接用
继承内存
方法区中加载该类的字节码文件,如果该类有父类,则要一同添加到方法区
创建新的类对象,如果该类是有继承父类的,则对象中会把空间分为两块
一块用来存父类的成员变量,一块存子类的成员变量
如果父类的成员变量变为私有private
能继承,但子类无法直接赋值
成员方法能否被继承
虚方法表:父类给子类的,包含经常用到的方法
只有虚方法才能被继承
Object有5个方法可以加载到虚方法表里
父类的private方法不能被继承
准确讲,父类中只有虚方法表中的成员方法能够被子类继承
继承中成员变量的特点
Name前面没有东西,就近原则
This.name 就是本类的成员变量name
Super.name 就是父类的成员变量name
子类中一次只能调用一个super,没有super.super.name
继承中成员方法的访问特点
一样是就近原则
This,super分别访问子类和父类的
重写父类的方法
方法重写的本质:子类覆盖了从父类继承的虚方法表里的方法
重写的时候,如果父类的方法比较多,可以直接super.eat();执行父类的方法
后面再写上子类的添加的重写内容
如果完全用不上父类的方法,就不用写super了,直接写上子类要重写的方法
方法重写总结
构造方法在继承中的访问方法
Super():默认调用父类的无参构造,一定要写在第一行,可以不写
Super(name,age):调用父类的有参构造,必须手写出来
This,super总结
This()同样要写在第一行,其实就是在调用空参构造时,给一个默认值,这样成员变量就不是空值了
练习
package exercise2;public class Test {public static void main(String[] args) {Lecturer lecturer = new Lecturer();lecturer.work();String name = lecturer.getName();System.out.println(name);}
}package exercise2;public class Employee {private String id;private String name;public Employee() {}public Employee(String id, String name) {this.id = id;this.name = name;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public void work(){System.out.println("员工在工作!");}
}package exercise2;public class Teacher extends Employee{public Teacher() {}public Teacher(String id, String name) {super(id, name);}}package exercise2;public class AdminStaff extends Employee{public AdminStaff() {}public AdminStaff(String id, String name) {super(id, name);}
}package exercise2;public class Lecturer extends Teacher{public Lecturer() {this(null,"zhansan");System.out.println("1111");}public Lecturer(String id, String name) {super(id, name);}@Overridepublic void work() {super.work();System.out.println("讲师在教书");}
}package exercise2;public class Tutor extends Employee{public Tutor() {}public Tutor(String id, String name) {super(id, name);}@Overridepublic void work() {super.work();System.out.println("助教在准备ppt");}
}package exercise2;public class Maintainer extends AdminStaff{public Maintainer() {}public Maintainer(String id, String name) {super(id, name);}@Overridepublic void work() {super.work();System.out.println("维护专员在维护");}
}package exercise2;public class Buyer extends AdminStaff{public Buyer() {}public Buyer(String id, String name) {super(id, name);}@Overridepublic void work() {super.work();System.out.println("采购员工在采购");}
}
多态
没有继承就没有多态
创建子类的对象赋值给父类的类型
多态
调用成员变量:编译看左边,运行也看左边
调用成员方法:编译看左边,运行看右边
多态
方法区在加载字节码文件,都是先加载父类的字节码文件,再加载子类的字节码文件
多态的优势
多态的弊端
不能调用子类的特有方法
如果要用,就要转换子类类型
A instanceof B:判断A是不是B类型的,返回true/false
JDK14之后
A instanceof B d:判断A是不是B类型的,如果是则转换为B类型,转换之后变量名为d,返回true/false
总结
根据需求完成代码:
1.定义狗类
属性:
年龄,颜色
行为:
eat(String something)(something表示吃的东西)
看家lookHome方法(无参数)
2.定义猫类
属性:
年龄,颜色
行为:
eat(String something)方法(something表示吃的东西)
逮老鼠catchMouse方法(无参数)
3.定义Person类//饲养员
属性:
姓名,年龄
行为:
keepPet(Dog dog,String something)方法
功能:喂养宠物狗,something表示喂养的东西
行为:
keepPet(Cat cat,String something)方法
功能:喂养宠物猫,something表示喂养的东西
生成空参有参构造,set和get方法
4.定义测试类(完成以下打印效果):
keepPet(Dog dog,String somethind)方法打印内容如下:
年龄为30岁的老王养了一只黑颜色的2岁的狗
2岁的黑颜色的狗两只前腿死死的抱住骨头猛吃
keepPet(Cat cat,String somethind)方法打印内容如下:
年龄为25岁的老李养了一只灰颜色的3岁的猫
3岁的灰颜色的猫眯着眼睛侧着头吃鱼
5.思考:
1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?
2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?
package exercise;public class Test {public static void main(String[] args) {Person keeper1 = new Person("老王", 30);Person keeper2 = new Person("老李", 25);// Cat cat = new Cat(3,"灰");
// Dog dog = new Dog(2,"黑");Animal cat = new Cat(3, "灰");Animal dog = new Dog(2, "黑");keeper1.keepPet(dog, "骨头");keeper2.keepPet(cat, "鱼");}
}package exercise;public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void keepPet(Dog dog, String something) {System.out.println("年龄为" + getAge() + "岁的" + getName() + "养了一只" + dog.getColor() + "颜色的" + dog.getAge() + "岁的狗");System.out.println(dog.getAge() + "岁的" + dog.getColor() + "颜色的狗两只前腿死死的抱住" + something + "猛吃");}public void keepPet(Cat cat, String something) {System.out.println("年龄为" + getAge() + "岁的" + getName() + "养了一只" + cat.getColor() + "颜色的" + cat.getAge() + "岁的猫");System.out.println(cat.getAge() + "岁的" + cat.getColor() + "颜色的眯着眼睛侧着头吃" + something);}public void keepPet(Animal animal, String something){System.out.println("年龄为" + getAge() + "岁的" + getName() + "养了一只" + animal.getColor() + "颜色的" + animal.getAge() + "岁的猫");System.out.print(animal.getAge() + "岁的" + animal.getColor());if (animal instanceof Cat cat){cat.eat("鱼");cat.catchMouse();} else if (animal instanceof Dog dog) {dog.eat("骨头");dog.lookHome();}}
}package exercise;public class Animal {private int age;private String color;public Animal() {}public Animal(int age, String color) {this.age = age;this.color = color;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public void eat(String something){}
}package exercise;public class Cat extends Animal {public Cat() {}public Cat(int age, String color) {super(age, color);}public void eat(String something) {System.out.println("颜色的眯着眼睛侧着头吃" + something);}public void catchMouse() {System.out.println("猫在抓老鼠");}
}package exercise;public class Dog extends Animal {public Dog() {}public Dog(int age, String color) {super(age, color);}public void eat(String something) {System.out.println("颜色的狗两只前腿死死的抱住" + something + "猛吃");}public void lookHome() {System.out.println("狗在看家");}
}