一 面向对象下二
1 抽象类和抽象方法(abstract)
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。
类的设计应该保证父类和子类能够共享特征。
有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
abstract:抽象的
abstract可以修饰的结构:类、方法
1.1 代码实例
public class AbstractTest{
public static void main(String[] args){
//Person p1 = new Person();
//Cannot instantiate the type Person
//一旦Person类抽象化了,就不能实例化了
}
}
abstract class Person{
//属性
String name;
int age;
//构造器
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//方法
public void eat(){
}
public void sleep(){
}
//抽象方法
public abstract void eat();
//toString重写
public String toSting(){
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
//this.name = name;
//this.age = age;
}
//The type Student must implement the inherited abstract method Person.eat()
public void eat(){
}
}
1.2 abstract修饰类:抽象类
abstract class Person{
}
- 此类不能实例化
- 抽象类中一旦有构造器,便于子类实例化调用(super()加载父类)
- 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
1.3 abstract修饰方法:抽象方法
public abstract void eat();
-
抽象方法只有方法的声明,没有方法体
-
包含抽象方法的类,一定是一个抽象类。
反之,抽象类中可以没有抽象方法的。
-
若子类重写了父类们中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类们中的所有抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
1.4 例子
1.5 使用注意点
- abstract不能用来修饰:属性、构造器等
- abstract不能用来修饰私有方法、静态方法、final的方法、final的类
2 抽象类的匿名子类(只用一次)
相当于临时重写了Person类中的抽象方法
//创建了一个匿名子类的对象:p
Person p = new Person(){
public void eat(){
}
}
public class Test{
public static void main(String[] args){
method(new Stuent());//匿名对象
Worker worker = new Worker();
method1(worker);//非匿名的类、非匿名的对象
method1(new Worker());//非匿名的类、匿名的对象
//匿名子类的非匿名对象
//创建了一个匿名子类的对象:p
Person p = new Person(){
public void eat(){
System.out.println("Eat");
}
};
method1(p);
//匿名子类的匿名对象
method1(new Person(){
public void eat(){
System.out.println("Eat");
}
})
}
public static void method(Student s){
}
public static void method1(Person p){
p.eat();
}
}
abstract class Person{
//属性
String name;
int age;
//构造器
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//方法
public void sleep(){
}
//抽象方法
public abstract void eat();
}
class Worker extends Person{
public void eat(){
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
//this.name = name;
//this.age = age;
}
//The type Student must implement the inherited abstract method Person.eat()
public void eat(){
}
}
3 抽象类的应用:模板方法设计模式(TemplateMethod)
public class TemplateTest{
public static void main(String[] args){
Template t = new SubTemplate();
t.spendTime();
}
}
abstract class Template{
//计算某段代码执行需要花费的时间
public void spendTime(){
long start = System.currentTimeMillis();
code();//不稳定的部分,一遍的部分
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
}
public abstract void code();
}
class SubTemplate extends Template{
@Override
public void code(){
for(int i = 2;i <= 1000;i++){
boolean isFlag =
}
}
}
4 接口(interface)
4.1 概念
4.2 举例
4.3 接口的使用
- 接口使用interface来定义
- Java中,接口和类是并列的两个结构
4.4 接口的定义(定义接口中的成员)
4.4.1 JDK7及以前
只能定义全局常量和抽象方法
- 全局常量:public static final的。但是书写时可以省略
- 抽象方法:public abstact的。
public class InterfaceTest{
public static void main(String[] args){
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);
Plane plane = new Plane();
plane.fly();
}
}
interface Flyable{
//全局常量
public static final int MAX_SPEED = 7900;
int MIN_SPEED = 1;
//int Min_SPEED = 1;//前面被省略了public static final,默认有public static final
//抽象方法
public abstact void fly();
void stop();//省略了public abstact
}
class Plane implements Flyable{
@Override
public void fly(){
System.out.println("飞机飞");
}
@Override
public void stop(){
System.out.println("飞机停");
}
}
4.4.2 JDK8
除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
-
接口中定义的静态方法,只能通过接口去调用
-
接口中定义的静态方法,可以通过实现类的对象去调用
如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写后的方法
-
如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法 — 类优先原则
-
如果实现类中实现了多个接口,而这多个接口定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,出错 — 接口冲突
这就需要我们必须在实现类中重写此方法
-
如何在子类(或实现)中调用父类、接口中被重写的方法
super.method3();//调用的是父类中声明的方法 CompareA.super.method3();//调用接口中的默认方法
public class SubClassTest{
public static void main(String[] args){
SubClass s = new SubClass();
//s.method1();//The method method1() is undefined for the type SubClass
//1.接口中定义的静态方法,只能通过接口来调用
CompareA.method1();
//2.接口中定义的静态方法,可以通过实现类的对象去调用
//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写后的方法
s.method2();//SubClass method2重写
//3.如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法 --- 类优先原则
s.method3();//SuperClass父类方法method3
}
}
public interface CompareA{
//静态方法(可以直接通过接口调用)
public static void metho1{
System.out.println("可以定义静态方法");
}
//默认方法(实现类里调用)
public default void method2{
System.out.println("CompareA接口可以定义默认方法");
}
default void method3{//省略了public,默认是有的
System.out.println("CompareA接口可以定义默认方法");
}
}
public interface CompareB{
default void method3{//省略了public,默认是有的
System.out.println("CompareB接口mthod3");
}
}
public class SuperClass{
public void method3{
System.out.println("SuperClass父类方法method3");
}
}
class SubClass extends SuperClass implements CompareA,CompareB{
@Override
public default void method2{
System.out.println("SubClass method2重写");
}
@Override
public default void method3{
System.out.println("SubClass method3重写");
}
//5.如何在子类(或实现)中调用父类、接口中被重写的方法
public void myMethod(){
method3();//自己定义的重写的方法
super.method3();//调用的是父类中声明的方法
CompareA.super.method3();//调用接口中的默认方法
CompareB.super.method3();
}
}
4.5 知识点
-
接口中不能定义构造器(意味着接口不可以实例化)
-
Java开发中,接口都通过让类去实现(interface)的方式来使用
- 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
- 如果实现类没有覆盖接口中的所有抽象方法,则此实现类仍未一个抽象类
-
Java类可以实现多个接口(弥补了Java单继承性的局限性)
格式:class AA extends BB implements CC,DD,EE
-
接口与接口之间可以继承,而且可以多继承
-
接口的具体使用,体现多态性
-
接口,实际上可以看作是一种规范
-
开发中,体会面向接口编程
public class USBTest{ public static main(String[] args){ Computer com = new Computer(); //1.创建了接口的【非匿名实现类】的【非匿名对象】 Flash flash = new Flash(); com.transferData(flash);//体现接口的多态性,填入接口的实现类 //USB usb = new Flash(); //2.创建了接口的【非匿名实现类】的【匿名对象】 com.transferData(new Printer()); //3.创建了接口的【匿名实现类】的【非匿名对象】 USB phone = new USB(){ @Override public void start(){ System.out.println("手机开始工作"); } @Override public void end(){ System.out.println("手机结束工作"); } }; com.transferData(phone); //4.创建了接口的【匿名实现类】的【匿名对象】 com.transferData(new USB(){ @Override public void start(){ System.out.println("手机开始工作"); } @Override public void end(){ System.out.println("手机结束工作"); } }) } } interface USB{//接口实际上定义了一种规范 int LENGTH = ?; int MAX_SPEED = 1024; int MIN_SPEED = 0; void start(); void end(); } class Flash interface USB{ @Override public void start(){ System.out.println("U盘开始工作"); } @Override public void end(){ System.out.println("U盘结束工作"); } } class Printer interface USB{ @Override public void start(){ System.out.println("打印机开始工作"); } @Override public void end(){ System.out.println("打印机结束工作"); } } class Computer{ public void transferData(USB usb){//形参要是USB实现类的对象 usb.start(); System.out.println("具体传输数据的细节"); usb.end(); } }
5 抽象类与接口的异同
6 接口的应用:代理模式(Proxy)
//静态代理
public class NetWorkTest{
public static main(String[] args){
Server server = new Server();
ProvyServer provyServer = new ProvyServer(server);
//server.browse();//为什么不直接这样,因为还要做check();
provyServer.browse();
}
}
interface NetWork{
public void browse();
}
//被代理类
class Server interface NetWork{
@Override
public void browse(){
System.out.println("真实的服务器访问网络");
}
}
//代理类
class ProxyServer interface NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work = work
}
public void check(){
System.out.println("联网之前的检查工作");
}
@Override
public void browse(){
check();
work.browse();
}
}
7 接口的应用:工厂模式
8 题目
8.1 直接父类与直接父类的相同x
就近原则
8.2 继承与接口的相同x
8.3 排错
8.4 包装类的比较
声明未包装类时(如:Double),可以调用包装类的方法比较大小(两个包装类是引用数据类型)
c1.compareTo(c2);
8.5 JDK8的接口特性
两接口有同名同参数方法,出错,重写才不出错
类优先原则
调用接口中的默认方法
9 类的成员之五:内部类
源码见,开发不常见
内部类举例:
Person可用name,age修饰,还要有一个大脑修饰,不可放在Person外修饰,且用简单的String修饰差点意思,这时可以用内部类修饰
- Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
9.1 内部类的分类
成员内部类(静态、非静态) VS 局部内部类(方法内、代码块内、构造器内)
public class InnerClassTest{
public static main(String[] args){
//9.2.1 如何实例化成员内部类的对象
//创建Dog实例(静态成员内部类)
Person.Dog dog = Person.Dog();//套娃
dog.show();
//创建Bird实例(非静态成员内部类)要有外部类的实例
Person p = new Person();
Person.Bird bird = p.new Bird();//奇葩
bird.show();
}
}
class Person{
String name;
int age;
public void eat(){
}
//静态成员内部类
abstract static class Dog{
String name;
int age;
public void show(){
}
}
//非静态成员内部类
class Bird{
String name;
int age;
public void show(){
eat();
//eat() == Person.this.eat();//套娃
}
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
}
//方法
public void method(){
//局部内部类
class AA{
}
}
//代码块
{
//局部内部类
class BB{
}
}
//构造器
public Person(){
//局部内部类
class CC{
}
}
}
9.1.1 成员内部类
一方面,作为外部类的成员:
- 调用外部类的结构
- 可以被static修饰
- 可以被4种不同的权限修饰
另一方面,作为一个类:
- 类可以定义属性、方法、构造器等
- 可以被final修饰,表示此类不能被继承。不使用final,就可以被继承
- 可以被abstract修饰,不能被实例化了
9.1.2 局部内部类
9.2 关注如下的3个问题
9.2.1 如何实例化成员内部类的对象
//创建Dog实例(静态成员内部类)
Person.Dog dog = Person.Dog();//套娃
dog.show();
//创建Bird实例(非静态成员内部类)要有外部类的实例
Person p = new Person();
Person.Bird bird = p.new Bird();//奇葩
bird.show();
9.2.2 如何在成员内部类中区分调用外部类的结构
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
9.2.3 开发中局部内部类的使用
public class InnerClassTest1{
//1.
//局部内部类
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//创建了一个实现了Comparable接口的类:局部内部类
class MyComparable implements Comparable{
@Override
public int compareTo(Object o){
return 0;
}
}
return new MyComparable();
}
//2.
//局部内部类
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//匿名实现类的匿名对面
return new Comparable(Object o){
@Override
public int compareTo(Object o){
return 0;
}
}
}
}