文章目录
1 多态
1.1 多态概述
多态:同一个对象(事物),在不同时刻体现出来的不同状态。
举例:
猫是猫,猫是动物。
水(液体,固体,气态)。
多态的前提:
A:要有继承关系。
B:要有方法重写。
其实没有也是可以的,但是如果没有这个就没有意义。
动物 d = new 猫();
d.show();
动物 d = new 狗();
d.show();
C:要有父类引用指向子类对象。
父 f = new 子();
1.2 多态成员访问特点
多态中的成员访问特点:
A:成员变量
编译看左边,运行看左边。
B:构造方法
创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
C:成员方法
编译看左边,运行看右边。
D:静态方法
编译看左边,运行看左边。
(静态和类相关,算不上重写,所以,访问还是左边的)
由于成员方法存在方法重写,所以它运行看右边。
总结:多态中,父类有的,展现到子类的不同,才可以叫多态,所以说,如果父类都没有,那么肯定编译错误
1.3 多态的优缺点
多态的好处:
A:提高了代码的维护性(继承保证)
B:提高了代码的扩展性(由多态保证)
多态的弊端:
A:不能使用子类的特有功能。
如何解决这个弊端:
多态的弊端:
不能使用子类的特有功能。
我就想使用子类的特有功能?行不行?
行。
怎么用呢?
A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
B:把父类的引用强制转换为子类的引用。(向下转型)
对象间的转型问题:
向上转型:
Fu f = new Zi();
向上转型时,父类只能调用父类方法或者子类覆写后的方法,而子类中的单独方法则是无法调用的.
向下转型:
Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。
向下转型容易出现的问题:
ClassCastException:类型转换异常,一般在多态的向下转型中容易出现
2 抽象类
2.1 抽象类概述
抽象类的概述:
动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的。
我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类。
抽象类的特点:
A:抽象类和抽象方法必须用abstract关键字修饰
B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
C:抽象类不能实例化
因为它不是具体的。
抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢?
答:用于子类访问父类数据的初始化
D:抽象的子类
a:如果不想重写抽象方法,该子类是一个抽象类。
b:重写所有的抽象方法,这个时候子类是一个具体的类。
抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
Animal a = new Cat();
//abstract class Animal //抽象类的声明格式
abstract class Animal {
//抽象方法
//public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体
public abstract void eat();
public Animal(){}
}
//子类是抽象类
abstract class Dog extends Animal {}
//子类是具体类,重写抽象方法
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
}
class AbstractDemo {
public static void main(String[] args) {
//创建对象
//Animal是抽象的; 无法实例化
//Animal a = new Animal();
//通过多态的方式
Animal a = new Cat();
a.eat();
}
}
2.2 抽象类的成员特点
抽象类的成员特点:
成员变量:既可以是变量,也可以是常量。
构造方法:有。
用于子类访问父类数据的初始化。
成员方法:既可以是抽象的,也可以是非抽象的。
抽象类的成员方法特性:
A:抽象方法 强制要求子类做的事情。
B:非抽象方法 子类继承的事情,提高代码复用性。
abstract class Animal {
public int num = 10;
public final int num2 = 20;
public Animal() {}
public Animal(String name,int age){}
public abstract void show();
public void method() {
System.out.println("method");
}
}
class Dog extends Animal {
public void show() {
System.out.println("show Dog");
}
}
class AbstractDemo2 {
public static void main(String[] args) {
//创建对象
Animal a = new Dog();
a.num = 100;
System.out.println(a.num);
//a.num2 = 200;
System.out.println(a.num2);
System.out.println("--------------");
a.show();
a.method();
}
}
2.3 抽象类的小问题
一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
A:可以。
B:不让创建对象。只能子类访问
abstract不能和哪些关键字共存?
private 冲突 无法继承
final 冲突 无法继承
static 冲突 static修饰的方法可以通过类名调用,然而调用一个没有方法体的抽象方法必然出错。
abstract class Fu {
//public abstract void show();
//非法的修饰符组合: abstract和private
//private abstract void show();
//非法的修饰符组合
//final abstract void show();
//非法的修饰符组合
//static abstract void show();
}
3 接口
3.1 接口概述
接口的特点:
A:接口用关键字interface表示
interface 接口名 {}
B:类实现接口用implements表示
class 类名 implements 接口名 {}
C:接口不能实例化
那么,接口如何实例化呢?
按照多态的方式来实例化。
D:接口的子类
a:可以是抽象类。但是意义不大。
b:可以是具体类。要重写接口中的所有抽象方法。(推荐方案)
由此可见:
A:具体类多态(几乎没有)
B:抽象类多态(常用)
C:接口多态(最常用)
举个例子:
//定义动物培训接口
interface AnimalTrain {
public abstract void jump();
}
//抽象类实现接口
abstract class Dog implements AnimalTrain {
}
//具体类实现接口
class Cat implements AnimalTrain {
public void jump() {
System.out.println("猫可以跳高了");
}
}
class InterfaceDemo {
public static void main(String[] args) {
//AnimalTrain是抽象的; 无法实例化
//AnimalTrain at = new AnimalTrain();
//at.jump();
AnimalTrain at = new Cat();
at.jump();
}
}
3.2 接口成员特点
接口成员特点
成员变量;只能是常量,并且是静态的。
默认修饰符:public static final
建议:自己手动给出。
构造方法:接口没有构造方法。
成员方法:只能是抽象方法。
默认修饰符:public abstract
建议:自己手动给出。
所有的类都默认继承自一个类:Object。
类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。
举个例子:
interface Inter {
public int num = 10;
public final int num2 = 20;
public static final int num3 = 30;
//错误: 需要<标识符>
//public Inter() {}
//接口方法不能带有主体
//public void show() {}
//abstract void show(); //默认public
public void show(); //默认abstract
}
//接口名+Impl这种格式是接口的实现类格式
/*
class InterImpl implements Inter {
public InterImpl() {
super();
}
}
*/
class InterImpl extends Object implements Inter {
public InterImpl() {
super();//Object的无参构造
}
public void show() {}
}
//测试类
class InterfaceDemo2 {
public static void main(String[] args) {
//创建对象
Inter i = new InterImpl();
System.out.println(i.num);
System.out.println(i.num2);
//i.num = 100;
//i.num2 = 200;
//System.out.println(i.num); //无法为最终变量num分配值
//System.out.println(i.num2);//无法为最终变量num2分配值
System.out.println(Inter.num);
System.out.println(Inter.num2);
System.out.println("--------------");
}
}
3.3 类与类,类与接口,接口与接口
类与类:
继承关系,只能单继承,可以多层继承。
类与接口:
实现关系,可以单实现,也可以多实现。
并且还可以在继承一个类的同时实现多个接口。
接口与接口:
继承关系,可以单继承,也可以多继承。
interface Father {
public abstract void show();
}
interface Mother {
public abstract void show2();
}
interface Sister extends Father,Mother {
}
//class Son implements Father,Mother //多实现
class Son extends Object implements Father,Mother {
public void show() {
System.out.println("show son");
}
public void show2() {
System.out.println("show2 son");
}
}
class InterfaceDemo3 {
public static void main(String[] args) {
//创建对象
Father f = new Son();
f.show();
//f.show2(); //报错
Mother m = new Son();
//m.show(); //报错
m.show2();
}
}
3.4 抽象类和接口的区别和联系
区别:
A:成员区别
抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
接口:
成员变量:只可以常量
成员方法:只可以抽象
B:关系区别
类与类
继承,单继承
类与接口
实现,单实现,多实现
接口与接口
继承,单继承,多继承
C:设计理念区别
抽象类 被继承体现的是:”is a”的关系。抽象类中定义的是该继承体系的共性功能。
接口 被实现体现的是:”like a”的关系。接口中定义的是该继承体系的扩展功能。
抽象类可以实现接口:
当你自己写的类想用接口中个别方法的时候(注意不是所有的方法),那么你就可以用一个抽象类先实现这个接口(方法体中为空),然后再用你的类继承这个抽象类,这样就可以达到你的目的了,如果你直接用类实现接口,那是所有方法都必须实现的;
3.5 形式参数和返回值的问题
(1)形式参数:
类名:需要该类的对象
抽象类名:需要该类的子类对象
接口名:需要该接口的实现类对象
(2)返回值类型:
类名:返回的是该类的对象
抽象类名:返回的是该类的子类对象
接口名:返回的是该接口的实现类的对象
4 权限修饰符
权限修饰符
本类 同一个包下 不同包下的子类 不同包下的无关类
private Y
默认 Y Y
protected Y Y Y
public Y Y Y Y
常见的修饰符(理解)
(1)分类:
权限修饰符:private,默认,protected,public
状态修饰符:static,final
抽象修饰符:abstract
(2)常见的类及其组成的修饰
类:
默认,public,final,abstract
常用的:public
成员变量:
private,默认,protected,public,static,final
常用的:private
构造方法:
private,默认,protected,public
常用的:public
成员方法:
private,默认,protected,public,static,final,abstract
常用的:public
(3)另外比较常见的:
public static final int X = 10;
public static void show() {}
public final void show() {}
public abstract void show();
5 内部类
5.1 内部类概述
内部类概述:
把类定义在其他类的内部,这个类就被称为内部类。
举例:在类A中定义了一个类B,类B就是内部类。
内部的访问特点:
A:内部类可以直接访问外部类的成员,包括私有。
B:外部类要访问内部类的成员,必须创建对象。
内部类位置
成员位置:在成员位置定义的类,被称为成员内部类。
局部位置:在局部位置定义的类,被称为局部内部类。
5.2 成员内部类
成员位置:在成员位置定义的类,被称为成员内部类。
class Outer {
private int num = 10;
//成员位置
/*
class Inner {
}
*/
public void method() {
//局部位置
class Inner {
}
}
}
class InnerClassDemo2 {
public static void main(String[] args) {
}
}
5.3 成员内部类的访问
成员内部类不是静态的:
外部类名.内部类名 对象名 = new 外部类名.new 内部类名();
成员内部类是静态的:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
案例1:private 保证安全
成员内部类的修饰符:
private 为了保证数据的安全性
static 为了方便访问数据
注意:静态内部类访问的外部类数据必须用静态修饰。
案例:我有一个人(人有身体,身体内有心脏。)
class Body {
private class Heart {
public void operator() {
System.out.println("心脏搭桥");
}
}
public void method() {
if(如果你是外科医生) {
Heart h = new Heart();
h.operator();
}
}
}
按照我们刚才的讲解,来使用一下
Body.Heart bh = new Body().new Heart();
bh.operator();
//加了private后,就不能被访问了,那么,怎么玩呢?
Body b = new Body();
b.method();
案例2:public static 便于访问
class Outer {
private int num = 10;
private static int num2 = 100;
//内部类用静态修饰是因为内部类可以看出是外部类的成员
public static class Inner {
public void show() {
//System.out.println(num);
System.out.println(num2);
}
public static void show2() {
//System.out.println(num);
System.out.println(num2);
}
}
}
class InnerClassDemo4 {
public static void main(String[] args) {
//使用内部类
// 限定的新静态类
//Outer.Inner oi = new Outer().new Inner();
//oi.show();
//oi.show2();
//成员内部类被静态修饰后的访问方式是:
//格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
Outer.Inner oi = new Outer.Inner();
oi.show();
oi.show2();
//show2()的另一种调用方式
Outer.Inner.show2();
}
}
5.4 局部内部类
见5.5案例
5.5 局部内部类访问局部变量的注意事项
局部内部类
A:可以直接访问外部类的成员
B:在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
面试题:
局部内部类访问局部变量的注意事项?
A:局部内部类访问局部变量必须用final修饰
B:为什么呢?
局部变量是随着方法的调用而调用,随着调用完毕而消失。
而这个时候局部对象并没有从堆内存中立即消失。为了能够继续使用这个局部变量,我们加final修饰。
加入final修饰后,这个变量就成了常量。既然是常量。你消失了。
我在内存中存储的是数据20,所以,我还是有数据在使用。
class Outer {
private int num = 10;
public void method() {
//int num2 = 20; 局部变量用完消失
final int num2 = 20;
class Inner {
public void show() {
System.out.println(num);
//从内部类中访问本地变量num2; 需要被声明为最终类型
System.out.println(num2);//20
}
}
//System.out.println(num2);
Inner i = new Inner();//等待垃圾回收器回收
i.show();//还会使用到num2,所以num2必须加final
}
}
class InnerClassDemo5 {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
6 匿名内部类
6.1 匿名内部类概述
匿名内部类
就是内部类的简化写法。
这里的类可以是具体类也可以是抽象类或者接口。
我们经常使用的是匿名对象
创建匿名对象的格式:
new 类名或者接口名(){
重写方法;
}
匿名对象的本质是什么呢?
new -> 对象
重写方法 -> 子类对象
最终 -> 是一个继承了该类或者实现了该接口的子类的匿名对象。
案例:
interface Inter {
public abstract void show();
public abstract void show2();
}
class Outer {
public void method() {
//匿名对象调用一个方法的时候
/*
new Inter() {
public void show() {
System.out.println("show");
}
}.show();
*/
//匿名对象调用二个方法的时候
//第一种写法:创建两个匿名对象分别调用方法
/*
new Inter() {
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
}.show();
new Inter() {
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
}.show2();
*/
//第二种写法,给匿名对象一个名字调用
Inter i = new Inter() { //多态
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
};
i.show();
i.show2();
}
}
class InnerClassDemo6 {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
6.2 匿名内部类在开发中的使用
举个栗子:
interface Person {
public abstract void study();
}
class PersonDemo {
//接口名作为形式参数
//其实这里需要的不是接口,而是该接口的实现类的对象
public void method(Person p) {
p.study();
}
}
//实现类
class Student implements Person {
public void study() {
System.out.println("好好学习,天天向上");
}
}
class InnerClassTest2 {
public static void main(String[] args) {
//测试
PersonDemo pd = new PersonDemo();
Person p = new Student();
pd.method(p);
System.out.println("--------------------");
//匿名内部类在开发中的使用
//匿名内部类的本质是继承类或者实现了接口的子类匿名对象
pd.method(new Person(){
public void study() {
System.out.println("好好学习,天天向上");
}
});
}
}
6.3 匿名内部类面试题
匿名内部类面试题:
按照要求,补齐代码
interface Inter { void show(); }
class Outer { //补齐代码 }
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
interface Inter {
void show();
//public abstract
}
class Outer {
//补齐代码
public static Inter method() {
//子类对象 -- 子类匿名对象
return new Inter() {
public void show() {
System.out.println("HelloWorld");
}
};
}
}
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
/*
1:Outer.method()可以看出method()应该是Outer中的一个静态方法。
2:Outer.method().show()可以看出method()方法的返回值是一个对象。
又由于接口Inter中有一个show()方法,所以我认为method()方法的返回值类型是一个接口。
*/
}
}