Java零基础学习Day15——面向对象进阶
一、抽象类
1. 定义
抽象方法
派生类的方法具体内容不同,抽取共性方法到基类
抽象类
类中存在抽象方法,则为抽象类
2. 格式
package last15;public class Test {public static void main(String[] args) {Person p = new Person();// 实例化,报错p.work();}
}
注意事项:
抽象类不能实例化
package last15;public class Test {public static void main(String[] args) {Person p = new Person();// 实例化p.work();}
}
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
package last15;public abstract class Person {public abstract void work();
}
package last15;public abstract class Person {public void sleep() {System.out.println("sleep");}
}
package last15;public class Person {public abstract void work();// 报错public void sleep() {System.out.println("sleep");}
}
可以有构造方法
package last15;public abstract class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public abstract void work();public void sleep() {System.out.println("sleep");}
}
抽象类的子类-要么重写抽象类的所有抽象方法(常用)、要么抽象类
Implements methods
package last15;public class Student extends Person {public Student() {}public Student(String name, int age) {super(name, age);}@Overridepublic void work() {System.out.println("学生的工作是学习");}
}
package last15;public abstract 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 abstract void work();public void sleep() {System.out.println("sleep");}
}
Make abstract
package last15;public abstract class Teacher extends Person {
}
3. 综合练习
package demo1;public abstract class Animal {private String name;private int age;public Animal() {}public Animal(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 drink() {System.out.println("Animal is drinking.");}public abstract void eat();
}
package demo1;public class Dog extends Animal {public Dog() {}public Dog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("狗吃骨头");}}
package demo1;public class Frog extends Animal{public Frog() {}public Frog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("青蛙吃虫子");}}
package demo1;public class Sheep extends Animal {public Sheep() {}public Sheep(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("山羊吃草");}}
package demo1;public class Test {public static void main(String[] args) {Frog f = new Frog("小黑", 1);System.out.println(f.getName()+" "+f.getAge());f.eat();f.drink();}
}
4. 意义
方便多人共同写代码,方便阅读代码
二、接口
1. 定义和使用
接口是一种规则
格式 :public interface 接口名 {}
使用:不可实例化
接口和类:public class 类名 implements 接口名 {}
public class 类名 implements 接口名1,接口名2 {}
public class 类名 extends 父类 implements 接口名1,接口名2 {}
接口和子类:要么重写接口中所有抽象方法、要么是抽象类
2. 练习
package demo1;public abstract class Animal {private String name;private int age;public Animal() {}public Animal(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 abstract void eat();
}
package demo1;public interface Swim {public void swim();
}
package demo1;public class Dog extends Animal implements Swim {public Dog() {}public Dog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("狗吃骨头");}@Overridepublic void swim() {System.out.println("狗刨");}
}
package demo1;public class Frog extends Animal implements Swim{public Frog() {}public Frog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("青蛙吃虫子");}@Overridepublic void swim() {System.out.println("青蛙在游泳");}
}
package demo1;public class Rabit extends Animal{public Rabit() {}public Rabit(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("兔子在吃胡萝卜");}
}
package demo1;public class Test {public static void main(String[] args) {Frog f = new Frog("小绿", 1);System.out.println(f.getName()+" "+f.getAge());f.eat();f.swim();Rabit r = new Rabit("小紫", 2);System.out.println(r.getName()+" "+r.getAge());r.eat();}
}
3. 接口中的成员特点
成员变量 | 只能是常量 默认修饰符:public static final |
构造方法 | 无 |
成员方法 | 只能是抽象方法 默认修饰符:public abstract JDK8可定义有方法体的方法 JDK9可定义私有方法 |
用内存进行分析
4. 接口和类
类和类:继承关系,单继承、多层继承
类和接口:实现关系,单实现、多实现、多接口
package demo3;public class InterImpl implements Inter1, Inter2{@Overridepublic void inter1() {}@Overridepublic void inter2() {}@Overridepublic void inter3() {}@Overridepublic void inter4() {}@Overridepublic void inter5() {}@Overridepublic void inter6() {}
}
package demo3;public interface Inter1 {public abstract void inter1();public abstract void inter2();public abstract void inter3();
}
package demo3;public interface Inter2 {public abstract void inter4();public abstract void inter5();public abstract void inter6();
}
接口和接口:继承关系,单继承、多继承
细节:如果是实现类实现了最下面的子接口,那么就需要重写所有抽象方法
package demo3;public interface Inter1 {public abstract void inter1();
}
package demo3;public interface Inter2 {public abstract void inter2();
}
package demo3;public interface Inter3 extends Inter1, Inter2{public abstract void inter3();
}
package demo3;public class InterImpl implements Inter3{@Overridepublic void inter3() {}@Overridepublic void inter1() {}@Overridepublic void inter2() {}
}
5. 综合练习
有多种思路
package Final_excise;public interface English {public abstract void speakEnglish();
}
package Final_excise;
// 因为直接创建基类人的对象此时是没有意义的,所以将其定义为抽象类
public abstract 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;}
}
package Final_excise;public abstract class Sporter extends Person {public Sporter() {}public Sporter(String name, int age) {super(name, age);}public abstract void study();
}package Final_excise;public abstract class Coach extends Person {public Coach() {}public Coach(String name, int age) {super(name, age);}public abstract void teach();
}
package Final_excise;public class PingPongCoach extends Coach implements English {public PingPongCoach() {}public PingPongCoach(String name, int age) {super(name, age);}@Overridepublic void teach() {System.out.println("乒乓球教练在教怎么打乒乓球");}@Overridepublic void speakEnglish() {System.out.println("乒乓球教练在说英语");}
}package Final_excise;public class BasketballCoach extends Coach {public BasketballCoach() {}public BasketballCoach(String name, int age) {super(name, age);}@Overridepublic void teach() {System.out.println("篮球教练在教怎么打篮球");}}
package Final_excise;public class PingPongSporter extends Sporter implements English {public PingPongSporter() {}public PingPongSporter(String name, int age) {super(name, age);}@Overridepublic void study() {System.out.println("乒乓球运动员在说英语");}@Overridepublic void speakEnglish() {System.out.println("乒乓球运动员在学习如何打乒乓球");}
}package Final_excise;public class BasketballSporter extends Sporter{public BasketballSporter() {}public BasketballSporter(String name, int age) {super(name, age);}@Overridepublic void study() {System.out.println("篮球运动员在学习如何打篮球");}}
package Final_excise;public class Test {public static void main(String[] args) {PingPongSporter pps = new PingPongSporter("孙颖莎", 25);System.out.println(pps.getName() + " " + pps.getAge());pps.study();pps.speakEnglish();}
}
6. 其他内容
JDK8开始接口中新增的方法
默认方法
接口中定义默认方法,用default修饰
作用:解决接口升级问题
格式:public default 返回值类型 方法名(参数列表){}
注意事项:默认方法不是抽象方法,不强制重写,若重写去掉default
若实现多个接口且存在同名默认方法,子类必须对该方法重写
静态方法
接口中定义静态方法,用static修饰
格式:public static 返回值类型 方法名(参数列表){}
注意事项:静态方法只能通过接口名调用,不能通过实现类名或对象名调用
私有方法
格式:private 返回值类型 方法名(参数列表){}
private static 返回值类型 方法名(参数列表){}
接口的应用
想让对应的java对象有对应的行为,就用接口即可
适配器设计模式
设计模式是解决各种问题的套路
适配器设计模式解决接口与接口实现类间的矛盾问题,即当一个接口抽象方法过多,但只需使用其中一部分时,就可以适配器设计模式
Inter接口里有五个方法,InterAdapter(抽象)则implements实现Inter重写Inter里的五个方法,InterImpl则extends继承InterAdapter,要用哪个方法就直接重写即可
三、内部类
内部类
定义:在一个类里定义一个类
规则:内部类表示的事物是外部类的一部分
内部类单独出现没有任何意义
访问:内部类可直接访问外部类的成员,包括私有的
外部类要访问内部类的成员,必须创建对象
使用场景:内部类表示外部类的一部分,且内部类单独存在没有意义
如汽车的发动机、ArrayList的迭代器、人的心脏等
分类:成员内部类(了解)、静态内部类(了解)、局部内部类(了解)、匿名内部类(掌握)
public class Car {String carName;int carAge;String carColor;public void show(){System.out.println("Car Name: " + carName);Engine e = new Engine();// 外部类不能直接访问内部类,需要创建内部类对象System.out.println("engine Name: " + e.engineName); }class Engine {String engineName;int engineAge;public void show(){System.out.println("engine Name: " + engineName);System.out.println("Car Name: " + carName);// 内部直接访问外部成员,包括私有System.out.println("Car Color: " + carColor);// 内部直接访问外部成员}}
}
成员内部类
位置
写在外部类的成员位置,private、默认、protected、public、static等
对象
两种方式
package demo1;public class Outer {String name;class Inner {}public Inner getInner() {return new Inner();}
}package demo1;public class Test {public static void main(String[] args) {Outer.Inner inner = new Outer().new Inner();//直接创建}
}
package demo1;public class Outer {String name;private class Inner {}public Inner getInner() {return new Inner();}
}package demo1;public class Test {public static void main(String[] args) {Outer o = new Outer();System.out.println(o.getInner());//外部类编写方法,对外提供内部类对象}
}
成员内部类获取外部类的成员变量
重名的变量
package demo1;public class Outer {private int a = 10;class Inner {private int a = 20;public void show() {int a = 30;System.out.println(a);System.out.println(this.a);System.out.println(Outer.this.a);}}
}
package demo1;public class Test {public static void main(String[] args) {Outer.Inner oi = new Outer().new Inner();oi.show();}
}
内存分析工具
静态内部类
访问
静态访问静态、非静态成员变量需创建外部类对象
package demo1;public class Outer {int a = 10;static int b = 100;static class Inner {public void show1() {//System.out.println(a);// 报错,静态方法只能访问静态成员变量System.out.println(b);// 正确,静态方法只能访问静态成员变量Outer o = new Outer();System.out.println(o.a);//访问非静态成员变量需创建外部类对象}public static void show2() {//System.out.println(a);// 报错,静态方法只能访问静态成员变量System.out.println(b);// 正确,静态方法只能访问静态成员变量Outer o = new Outer();System.out.println(o.a);//访问非静态成员变量需创建外部类对象}}
}
对象
创建静态内部类对象、调用静态内部类方法
package demo1;public class Outer {int a = 10;static int b = 100;static class Inner {public void show1() {System.out.println("非静态方法被调用");}public static void show2() {System.out.println("静态方法被调用");}}
}package demo1;public class Test {public static void main(String[] args) {Outer.Inner oi = new Outer.Inner();// 直接创建静态内部类对象oi.show1();// 调用非静态方法Outer.Inner.show2();// 调用静态方法}
}
局部内部类
位置
将内部类定义在方法里面,类似方法里的局部变量,不能用public
对象
需在方法内部创建对象并使用
访问
该类可直接访问外部类成员,也可访问方法内的局部变量
package demo1;public class Outer {// 外部类int a = 20;public void show() {int b = 10;// 局部变量class Inner {// 局部内部类String name;int age;public void method1() {System.out.println(a);// 访问外部类的成员变量System.out.println(b);//访问方法内的局部变量System.out.println("局部变量里的method1方法");}public static void method2() {System.out.println("局部变量里的method1静态方法");}}Inner i = new Inner();//在方法内部创建对象System.out.println(i.name);//访问局部内部类的成员变量System.out.println(i.age);i.method1();//访问局部内部类的成员方法Inner.method2();//访问局部内部类的静态方法}
}package demo1;public class Test {public static void main(String[] args) {Outer o = new Outer();o.show();}
}
匿名内部类
定义
隐藏了名字的内部类,在成员位置或局部位置都可
格式
new 类名或接口名(){
重写方法;
};
具体包含的内容有:继承\实现、方法重写、创建对象
package demo1;public class Test {public static void main(String[] args) {new Swim(){// new表示创建对象、Swim()表示是实现和继承@Override// 方法重写public void swim() {System.out.println("重写了游泳的方法");}};}
}
package demo1;public interface Swim {public abstract void swim();
}
字节码文件即class文件里,外部类名字是有的,只是不需要手动去设置
javap反编译终端命令
使用
只用一次时可以使用匿名内部类
package demo1;public class Test {public static void main(String[] args) {new Swim(){// new表示创建对象、Swim()表示是实现和继承@Override// 方法重写public void swim() {System.out.println("重写了游泳的方法");}};Dog d = new Dog();//Dog类继承Animal类,创建Dog对象method(d);//将Dog对象作为参数传递给method方法//若dog类只用一次,可以使用匿名内部类method(new Animal(){@Overridepublic void eat() {System.out.println("狗吃骨头");}});}public static void method(Animal a) {a.eat();}
}
package demo1;public abstract class Animal {public abstract void eat();
}package demo1;public class Dog extends Animal{@Overridepublic void eat() {System.out.println("狗吃骨头");}
}
方法调用
匿名内部类可以整体理解为一个类的子类对象或者接口的实现类对象
package demo1;public class Test {public static void main(String[] args) {//接口多态Swim s = new Swim(){@Overridepublic void swim() {System.out.println("重写了游泳的方法");}};//编译看左边,运行看右边s.swim();new Swim(){@Overridepublic void swim() {System.out.println("重写了游泳的方法");}}.swim();}
}