继承
概念
将编程对象的共性抽取出来,减少代码的重复
如:猫和狗都是动物
那么animal在Java中称之为父类,猫和狗称之为子类。子类可以复用父类的成员变量和方法
语法
修饰符 class 子类 extends 父类 {
//代码
}
如将猫狗写成动物的子类,代码如下
public class Animal{
String name;
int age;
public void eat(){
System.out.println(name + "正在吃饭");
}
public void sleep(){
System.out.println(name + "正在睡觉");
}
}
public class Dog extends Animal{
void bark(){
System.out.println(name + "汪");
}
}
public class Cat extends Animal{
void mew(){
System.out.println(name + "喵");
}
}
public class Test{
public static void main(String[] args) {
Dog dog = new Dog();
System.out.println(dog.name);
System.out.println(dog.age);
dog.eat();
dog.sleep();
dog.bark();
//创建Cat同理
}
}
子类继承父类后应该添加成员或方法,否则和父类一样就没必要继承了
父类成员的访问
子类和父类无同名成员:
直接访问
子类和父类成员同名:
在子类中访问到的是子类的成员
访问父类成员方法:
采用如下关键字访问
super
访问父类成员:
super.父类成员名
访问父类方法:
super.父类方法名()
访问父类构造方法:
super(参数)
注意:
super只能在非静态方法中使用
子类构造方法
当子类构造前,需要先构造父类
因此在子类的构造方法中会默认调用super()
注意:
如果父类的构造方法是带参数的,那么程序员需要自己写子类的构造方法,并且用super调用正确的父类构造方法
super()必须是子类构造方法中的第一条语句
super()与this不能同时出现
对比super与this
相同点:
只能在非静态方法使用,访问非静态成员
构造方法调用时必须在第一条语句
不同点:
this是对当前对象的引用,super是对父类的引用
this是隐藏参数,super不隐藏
构造方法中两者不能同时出现
初始化代码执行顺序
class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person:构造方法执行");
}
{
System.out.println("Person:实例代码块执行");
}
static {
System.out.println("Person:静态代码块执行");
}
}
class Student extends Person{
public Student(String name,int age) {
super(name,age);
System.out.println("Student:构造方法执行");
}
{
System.out.println("Student:实例代码块执行");
}
static {
System.out.println("Student:静态代码块执行");
}
}
public class Test{
public static void main(String[] args) {
Student student1 = new Student("wang",13);
System.out.println("————————————————————————————");
Student student2 = new Student("zhang",13);
}
public static void main1(String[] args) {
Person person1 = new Person("li",18);
System.out.println("————————————————————————————");
Person person2 = new Person("zhao",22);
}
}
Person:静态代码块执行
Student:静态代码块执行
Person:实例代码块执行
Person:构造方法执行
Student:实例代码块执行
Student:构造方法执行
————————————
Person:实例代码块执行
Person:构造方法执行
Student:实例代码块执行
Student:构造方法执行
以上代码说明:
父类的静态代码块优先于子类执行,然后执行子类静态代码块
父类的实例和构造代码块接着执行,再执行子类的实例和构造代码块
第二次实例化对象,父类和子类的静态代码块不再执行
在之前的类与对象的blog中,有关于修饰符的表格
注意:
Java只支持单继承
final
final就像c语言中的const关键字一样
当修饰变量时,使其变为常量
当修饰类时,使其不能被继承
当修饰方法时,使其不能被重写(后续提到)
多态
概念
不同对象对同一行为的完成方式不同
如何实现
1使用继承
2子类对父类的方法进行重写
3子类用父类的引用调用被重写的方法
public class Animal {
String name;
int age;
public Animal(String name, int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(name + "吃饭");
}
}
public class Cat extends Animal{
public Cat(String name, int age){
super(name, age);
}
@Override
public void eat(){
System.out.println(name+"吃鱼");
}
}
public class Dog extends Animal {
public Dog(String name, int age){
super(name, age);
}
@Override
public void eat(){
System.out.println(name+"吃骨头");
}
}
public class Test{
public static void eat(Animal a){
a.eat();
}
public static void main(String[] args) {
Cat cat = new Cat("黑",7);
Dog dog = new Dog("白", 5);
eat(cat);
eat(dog);
}
}
可以看到,子类中也有父类的方法,这个override代表重写。当main调用eat方法时,子类以父类的类型进行传入,这时调用的便是子类对父类方法重写后的方法
重写
1.方法名,修饰符,返回类型,参数都应该完全一致,以下有特殊
2.重写的返回值可以不同,但必须是父子类关系的,即协变类型
3.子类重写的访问权限不能低于父亲
4.static,final修饰的方法不能被重写
5.用override代表方法被重写
与重载的区别
区别 | 重载 | 重写 |
---|---|---|
参数 | 必须修改 | 不能修改 |
返回类型 | 可以修改 | 不能修改 |
访问限定符 | 可以修改 | 不小于父类权限 |
静态绑定
即在编译时就知道调用哪个方法,典型例子为重载
动态绑定
即在运行时才能知道调用哪个方法,典型例子为重写
向上转型
即子类对象转换为父类进行使用
有以下几种转换方法:
1.直接赋值
2.方法传参
3.方法返回
缺点:
无法调用子类的特有方法
向下转型
public class Test{
public static void main(String[] args) {
Cat cat = new Cat("黑",7);
Dog dog = new Dog("白", 5);
// 向上转型
Animal animal = cat;
animal.eat();
animal = dog;
animal.eat();
if(animal instanceof Cat){
cat = (Cat)animal;
cat.mew();
}
if(animal instanceof Dog){
dog = (Dog)animal;
dog.bark();
}
}
}
instanceof
这个可以判断是否引用其子类成员,向下转型有风险,建议少用