目录
一,继承
1.什么是继承
1.是一种可以使代码复用的手段,以实现共性的抽取。
2.派生类/子类:在原有类(父类/基类/超类)的基础上进行扩展,以增加新功能。
2.怎样实现继承
使用extends关键字,如
public class TestExtends {
public static void main(String[] args) {
Apple apple=new Apple();
System.out.println(apple.color);//父类的成员变量继承到了子类里
System.out.println(apple.name);
System.out.println(apple.kg);
}
}
class Fruit{
String name;
String color;
}
class Apple extends Fruit{
String kg;//仔细想想,如果什么都不添加,那还用继承干嘛?
}
1.父类成员变量继承到了子类里
2.子类必须添加新的部分,体现出与父类的不同
3.父类成员访问
(1)子类中访问父类的成员变量
1. 子类和父类不存在同名成员变量
public class Base {
int a;
int b;
}
public class Derived extends Base{
int c;
public void method(){
a = 10; // 访问从父类中继承下来的a
b = 20; // 访问从父类中继承下来的b
c = 30; // 访问子类自己的c
}
}
2. 子类和父类成员变量同名,优先子类
public class Base {
int a;
int b;
int c;
}
public class Level extends Base{
int a; // 与父类中成员a同名,且类型相同
char b; // 与父类中成员b同名,但类型不同
public void method(){
a = 100; // 子类的a
b = 101; // 子类的b
c = 102; // 父类的c
}
}
(2) 子类中访问父类的成员方法
1.成员方法名字相同
参数列表不同则构成重载,参数列表相同访问子类
public class Base {
public void methodA(){ }
public void methodB(){ }
}
public class Derived extends Base{
public void methodA(int a) { }
public void methodB(){ }
public void methodC(){
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
methodB(); // 永远访问子类中的methodB()
}
}
2.成员方法名字不同
优先访问自己的方法,自己没有时,再到父类中找,如果父类中也没有则报错。
4.super关键字
主要作用:在子父类出现相同名称的成员时,子类方法中访问父类的成员。
【注意】
1. 只能在非静态方法中使用
2. 在子类方法中,访问父类的成员变量和方法。
public class Base {
int a=1;
int b=2;
public void methodB(){
System.out.println("Base中的methodB()");}
}
public class Derived extends Base{
int a=3; // 与父类中成员变量同名且类型相同
char b=4; // 与父类中成员变量同名但类型不同
public void methodB(){
System.out.println("Derived中的methodB()");
}
public void methodC(){
a=5;b=6;methodB();//访问的都是子类的
// 访问父类的成员时,需要借助super关键字
super.a = 5;
super.b = 6;
super.methodB(); //不要忘记"."!
}
}
5.子类构造方法
新建子类构造方法时,需要先调用基类构造方法,然后再执行子类的构造方法。
public class Base {
public Base(){
System.out.println("Base()");
}
}
public class Derived extends Base{
public Derived(){
super();
// 用户没有写时,编译器会自动添加(必须是无参父类构造方法)
// super()必须是子类构造方法中第一条语句
// 只能出现一次
System.out.println("Derived()");
}
}
public class Test {
public static void main(String[] args) {
Derived d = new Derived();
}
}
//结果打印:
//Base()
//Derived(
【注意】
1. 若父类定义无参或者默认的构造方法时,在子类构造方法第一行默认super()调用
2. 如果父类构造方法是带有参数的,则不会再给子类生成默认的构造方法,此时需要用户在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。
4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现
(1)this和super的区别
【相同点】
1. 都是Java中的关键字
2. 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
3. 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
【不同点】
1. this是当前对象的引用,super是子类对父类部分成员的引用
2. 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类的方法和属性
3. this是非静态成员方法的一个隐藏参数,super不是隐藏的参数
4. 在构造方法中:this(...)用于调用本类构造方法,super(...)用于调用父类构造方法,两种调用不能同时在构造方法中出现
5. 构造方法中一定会存在super(...)的调用,但是this(...)不写则没有
6.继承关系上的执行顺序
第一次实例化子类对象时:
父类静态代码块>子类静态代码>父类实例代码块>父类构造方法>子类的实例代码块>子类构造方法
第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行
什么?你忘了什么是代码块?
class Person {
public String name;
public int age;
//构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("构造方法执行");
}
//实例代码块
{
System.out.println("实例代码块执行");
}
//静态代码块
static {
System.out.println("静态代码块执行");
}
}
7.继承的种类
(1)单继承
Class A——》Calss B
public class A{}
public class B extends A{}
(2)多层继承
Class A——》Calss B——》Class C(一般不超过3层)
public class A{}
public class B extends A{}
public class C extends B{}
(3)不同类继承同一类
Class B——》Calss A
Class C——》Calss A
public class A{}
public class B extends A{}
public class C extends A{}
(4)不支持多继承
一个类不能又继承A又继承B,脚踏两条船
8.final关键字
1. 修饰变量或字段,表示常量(不能修改)
final int a = 10;
a = 20; // 编译出错
2. 修饰类:表示此类不能被继承
final public class Animal {
...
}
public class Bird extends Animal {
...
}
// 编译出错
3. 修饰方法:表示该方法不能被重写
(9)组合与继承的区别
组合更像是通过部件将一个物体组合起来,而继承则像是小物体与大物体是上下延续关系
// 轮胎类
class Tire{}
// 发动机类
class Engine{}
// 车载系统类
class VehicleSystem{}
class Car{
private Tire tire; // 可以复用轮胎中的属性和方法
private Engine engine; // 可以复用发动机中的属性和方法
private VehicleSystem vs; // 可以复用车载系统中的属性和方法
}
// 奔驰是汽车
class Benz extend Car{
// 将汽车中包含的:轮胎、发送机、车载系统全部继承下来
}
二,多态
1.什么是多态
当不同的对象去完成同一个事时,产生出的不同状态。
2.多态实现条件
1. 必须在继承体系下
2. 子类必须要对父类中方法进行重写(返回值和形参不做改变,改变方法中的内容)
public class A{
public void eat(){}
}
重写A中方法eat(),{ }中内容记得改变,这里为了直观体现就不填写内容了
public class C extends A{
public void eat(){}
}
public class D extends A{
public void eat(){}
}
【方法重写的规则】
(1)子类在重写父类的方法时,一般必须与父类方法原型一致:修饰符 返回值类型 方法名(参数列表) ,返回值类型可以不同,但必须是有子父类关系
(2)访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected
(3)父类被static、private修饰的方法、构造方法都不能被重写。
(4)重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验.
3. 通过父类的引用调用重写的方法
a这个引用调用eat方法的这种行为就称为多态.一次调用,以后将可能会出现c与d两种表现
public static void eat(父类 a){
a.eat();//这里a调用的不知道是哪个子类,c或是d
}
4.再在main中使用
public static void main(String[] args) {
C c=new C();
D d=new d();
eat(c);
eat(d);
}
3.向上转型
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
Animal animal = new Cat("元宝",2);
父类类型 对象名= new 子类类型();
public class TestAnimal {
public static void main(String[] args) {
// 1. 直接赋值:子类对象赋值给父类对象
Animal cat = new Cat("元宝",2);
Animal dog = new Dog("小七", 1);
eatFood(cat);
eatFood(dog);
Animal animal = buyAnimal("狗");
animal.eat();
Animal animal2 = buyAnimal("猫");
animal2.eat();
}
// 2. 方法传参:形参为父类型引用,可以接收任意子类的对象
public static void eatFood(Animal a){
a.eat();
}
// 3. 作返回值:返回任意子类对象
public static Animal buyAnimal(String var){
if("狗" == var){
return new Dog("狗狗",1);
}else if("猫" == var){
return new Cat("猫猫", 1);
}else{
return null;
}
}
}
向上转型的优点:让代码实现更简单灵活。
向上转型的缺陷:不能调用到子类特有的方法。
4.向下转型
将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。
//向上转型
Animal animal = cat;
cat,mew();//无法编译
//向下转型
cat = (Cat)animal;
cat.mew();//mew()是Cat特有的方法,编译成功
但向下转型往往是不安全的,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换。
if(animal instanceof Cat){
cat = (Cat)animal;
cat.mew();
}
5.多态的优缺点
(1)优点
1. 能够降低代码的 "圈复杂度", 避免使用大量的 if - else
2. 可扩展能力更强
(2)缺点
1.代码的运行效率降低