1、抽象类:
使用某个类描述事物的时候,如果这个类中在描述这个事物的某个行为或功能的时候,只知道这个事物有这个行为或功能,但没有办法书写清楚具体的功能体,函数体,这时可以使用抽象函数来表示这个行为或功能,由于类中有抽象的函数,这个类就会变成抽象类。
注意事项
1、子类在继承抽象类后,需要把抽象类中所有的抽象方法全部复写(重写)完成。抽象类中定义所有子类的共性行为,然后由具体的子类针对自己的实际情况复写父类提供的基本行为,建立适合自己的功能体。
2、抽象类和一般类有什么区别?
抽象类肯定需要abstract修饰,一般类不能使用。
不管是抽象类,还是一般类,它们都是描述事物体系中的某个事物,只不过抽象类描述的一定是这个事物体系中的共性内容,抽象类不一定是最顶层的类,但一定不是最底层的类。
3、抽象类有没有构造函数,能不能创建对象?
有构造函数,但不能创建对象。
构造函数是给成员变量初始化的,抽象类中的构造函数就是为了子类对象初始化使用的,因为抽象类一定有子类,而创建子类对象的时候,在子类的构造函数中一定有super()语句会找自己的父类构造函数进行初始化动作。
1)定义一个抽象类Animal作为父类,在这个父类中定义一个带有一个参数的构造函数,接收子类传递过来的值,并打印;
2)在抽象类Animal中定义一个抽象函数eat;
3)再定义一个Cat猫类,让这个猫类继承Animal类,在这个Cat类中定义一个构造函数,在构造函数中使用super调用Animal中的构造函数;
4)在类Cat中复写eat函数;
5)定义一个测试抽象类,并在这个类中创建Cat的对象;
abstract class Animal
{
Animal(int b)//抽象类中的有参构造函数
{
System.out.println(b);
}
abstract void eat();
}
class Cat extends Animal
{
Cat()
{
super(3);
}
void eat(){}
}
class AbstractDemo
{
public static void main(String[] args)
{
Cat c=new Cat();
}
}
演示抽象类不能实例化,也就是说抽象类不能创建对象。
抽象类一定是个类,类中肯定就会有构造函数。抽象类不能创建对象的原因是抽象类中有抽象函数,如果我们可以直接创建抽象类的对象,那么就可以使用这个对象调用那个抽象函数,而抽象函数是没有函数体的函数,调用函数的最终目的是需要函数体的执行,完成我们想要的结果。因此我们如果可以创建抽象类的对象,那么就会导致可以调用抽象函数,而调用了抽象函数,却得不到任何想要的效果。这样的做法没有意义。因此sun公司在指定抽象类的规则时,不让程序直接创建抽象类的对象。
4、抽象类一定是父类吗?
一定是父类,一定不是顶层父类。
抽象类中通常都有抽象函数,而抽象类中的抽象函数要求必须由子类来复写(由具体的子类来实现其中的函数体)。
子类的主要作用是复写抽象类中的抽象函数。
5、抽象类可以继承其他类吗?
抽象类也是一个类,因此它必须具备类的继承特点。它可以有父类。
6、抽象关键字不能和哪些关键字共存?
private修饰符:表示私有的。
private :父类中私有的成员,子类是不知道的,因此使用private 和abstract关键字一起修饰函数,导致子类根本无法知道父类中有个抽象函数,同时也导致了子类不能复写父类中的方法。
static修饰符:表示静态的。
static:如果使用static和abstract关键字一起修饰抽象函数,导致这个函数可以使用类名直接调用,而抽象函数是没有方法体的,调用这个抽象函数是没有意义的。
final修饰符:表示最终的。(先了解)
final :final修饰的函数子类是无法复写的,而abstract修饰的函数,要求子类必须复写。
抽象类何时使用:
当描述事物体系,一般在描述所有体系中最共性的内容时,通常是只知道体系的共性功能,却不能书写具体功能体,这时会使用抽象函数表示,那么这个类一定会使用抽象类表示。
抽象类存在的意义
抽象类:在描述事物的时候,没有足够的信息描述一个事物,这时该事物就是抽象事物。抽象类存在的意义和我们之前学过的父类存在思想是一样的,那么有父类到底有什么好处呢?父类有抽象和非抽象的,但是都一样,父类或抽象类的存在让我们面对事物发生了改变,我们不要再去面对具体的子类事物,直接面对父类就可以了。
将类定义为抽象类时,这样别人看到你的代码,或你看到别人的代码,你就会注意抽象方法,而知道这个方法是在子类中实现的,所以,有个提示作用。(子类一定要复写父类中的抽象方法)
举例:问你个问题,你知道什么是“东西”吗?什么是“物体”吗?
“麻烦你,小黑。帮我把那个东西拿过来好吗”
在生活中,你肯定用过这个词--东西。
小黑:“你要让我帮你拿那个水杯吗?”
你要的是水杯类的对象。而东西是水杯的父类。通常东西类没有实例对象,但我们有时需要东西的引用指向它的子类实例。
总结:抽象类存在的意义是为了被子类继承,否则抽象类将毫无意义,抽象类体现的是模板思想,模板是通用的东西。模板中不能决定的东西定义成抽象方法,让使用模板(继承抽象类的类)的类去重写抽象方法实现需求,这是典型的模板思想。
二、内部类
概述
什么是内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。可以把内部类理解成寄生,外部类理解成宿主。 内部类是Java类的五大成员之一,也是我们最后一个需要学习的成员。
按定义的位置来分
1. 成员内部类,类定义在了成员位置 (类中方法外称为成员位置)
2. 匿名内部类。定义在局部位置
成员内部类成员内部类特点:
- 无static修饰的内部类,属于外部类对象的。
- 宿主:外部类对象。 ```java 外部类.内部类。 // 访问内部类的类型都是用 外部类.内部类
外部类.内部类 变量 = new 外部类构造器.new 内部类构造器;
class Outer02{
// 实例内部类,属于外部类对象的。
// 拓展:实例内部类不能定义静态成员。
public class Inner02{
// 这里面的东西与类是完全一样的。
private String name;
public Inner02(String name) {
this.name = name;
}
public void showName(){
System.out.println(this.name);
}
}
}
public class InnerClassDemo02 { public static void main(String[] args) { // 宿主:外部类对象。 // Outer02 out = new Outer02(); // 创建内部类对象。 Outer02.Inner02 in = new Outer02().new Inner02(“张三”); in.showName(); } } Outer.Inner in=new Outer().new Inner();表示使用外部类的匿名对象new Outer()调用内部类的对象重新赋值给一个变量in。这里的in就表示内部类对象名。 注意:上述代码中,当外部类Outer.class被加载到内存中的时候,内部类Outer$Inner.class还没有被加载到内存中,仍然在硬盘中,只有当创建对象的时候使用内部类的时候,jvm才会将Outer$Inner.class加载到内存中。
<a name="KjiUO"></a>
### 成员内部类面试题
```java
// 身体
class Body {
private int weight = 30;
// 在成员位置定义一个类
class Heart {
private int weight = 20;
public void jump() {
System.out.println("局部内部类函数this="+this);
System.out.println("外部类this="+Body.this);
int weight = 10;
System.out.println("心脏在跳动 " + weight); // 10
System.out.println("心脏在跳动 " + this.weight); // 20
System.out.println("心脏在跳动 " + Body.this.weight); // 30
}
}
}
public class Demo05 {
public static void main(String[] args) {
Body b = new Body();
System.out.println("b="+b);
Body.Heart heart = new Body().new Heart();
System.out.println("heart="+heart);
heart.jump();
}
}
匿名内部类【重点】
概述
匿名内部类 :是内部类的简化写法。它的本质是一个带具体实现的父类或者父接口的匿名的子类对象。开发中,最常用到的内部类就是匿名内部类了。
匿名内部类前提和格式
匿名内部类必须继承一个父类或者实现一个父接口。
new 父类名或者接口名(){
// 方法重写
@Override
public void method() {
// 执行语句
}
};
说明:
1.其实上述整体格式是父类或者父接口的子类对象
2.
{
// 方法重写
@Override
public void method() {
// 执行语句
}
}
这些内容称为匿名内部类。但是不能单独书写,必须结合上述new 父类名或者接口名()一起。
匿名内部类的特点
- 定义一个没有名字的内部类
- 这个类实现了父类,或者父类接口
- 匿名内部类会创建这个没有名字的类的对象