面向对象(三)

抽象类

抽象类用abstract进行修饰。

在前面的学习我们知道,所有的对象都是通过类来描绘的,但是不是所有的类都是用来描述对象的,如果一个类中没有足够的成员来描绘一个具体的对象,那这个类就是抽象类。

简而言之,抽象类里面可以什么东西都不用去实现,只留有一个大概的框架,作为对后面继承的子类的约束。

抽象类里面可以有正常的方法,也可以有用abstract修饰的抽象方法,抽象方法也同样是可以不去实现的。

实际上受限于Java只能单继承,抽象类使用并不如接口常见。

总结一下,抽象类的特点:

  1. 抽象类无法实例化,也就是无法new出来,它需要靠子类去实现它;
  2. 子类继承抽象类需要实现抽象类内的内容,除非子类也是个抽象类;
  3. 抽象类里可以写普通方法,但是抽象方法必须在抽象类中;静态方法,也就是被static修饰的方法,不能被声明为抽象方法;
  4. 抽象类含有构造器,是为了被子类继承,子类必须调用父类构造器。

例子

Demo:

1
2
3
4
5
6
7
public class Demo {
public static void main(String[] args) {
Student student = new Student();
student.run();//out:I am running.
student.say();//out:I am studying.
}
}

Person(抽象类):

1
2
3
4
5
6
public abstract class Person {
public abstract void say();
public void run(){
System.out.println("I am running.");
}
}

Student(子类):

1
2
3
4
5
6
public class Student extends Person{
@Override
public void say() {
System.out.println("I am studying.");
}
}

接口

接口与抽象类比较相似,但它并不是一个类,因此他并不是用class来声明,而是使用interface。抽象类和接口的区别在于,抽象类可以有具体实现和抽象方法,而接口只存在抽象方法。

接口是对类的实现进行一种约束,也就是一种你是什么就应该做什么的规范,也就是例如,人你就得会吃饭,汽车你就得会跑,但是你怎么吃饭,汽车怎么跑,这是类应该去描绘的内容。接口实现了约束和实现的分离。

接口的特性

  1. 接口中的方法都是public abstract的,而且只能是public abstract的;
  2. 接口中可以含有变量,但是变量都是public static final的,而且只能是public的;
  3. 接口中的方法是不能在接口中实现的,只能由实现接口的来实现接口的方法。

类用implements关键词来实现接口。跟抽象类一样,实现了接口的类,就需要重写接口中的方法。与只能继承一个抽象类不同,类可以实现多个接口。

接口和接口直接也是可以互相继承的,同样也是使用extend来继承。虽然他有继承关系,但是接口里是不存在构造器的。

例子

PersonImple:

1
2
3
4
5
6
7
8
public class PersonImpl implements Person,Clothes{
@Override
public void run() {}
@Override
public void color() {}
@Override
public void say() {}
}

Animal:

1
2
3
public interface Animal {
void run();
}

Person:

1
2
3
public interface Person extends Animal{
void say();
}

Clothes:

1
2
3
public interface Clothes {
void color();
}

内部类

内部类是在一个类的内部再定义一个类。

成员内部类

由于该内部类嵌套在外部类内,我们需要先实例化外部类,然后再通过外部类实例化的对象来实例化内部类。

内部类是可以访问到外部类的私有成员的。

Demo:

1
2
3
4
5
6
7
public class Demo {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.get();//out:外部类
}
}

Outer:

1
2
3
4
5
6
7
8
public class Outer {
private String str = "外部类";
public class Inner{
public void get(){
System.out.println(str);
}
}
}

内部类可以使用privateprotected来修饰,如果你不希望内部类被外部类访问可以使用private 修饰符。

静态内部类

静态内部类可以使用 static 关键字定义,静态内部类就不需要先实例化外部类再实例化内部类了,可以直接实例化内部类。

如果外部类是非静态的,而内部类是静态的,那么内部类就无法在外部类实例化之前调用外部类的成员了。

Demo:

1
2
3
4
5
6
public class Demo {
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner();
System.out.println(inner.str2);//out:内部类
}
}

Outer:

1
2
3
4
5
6
public class Outer {
String str = "外部类";
public static class Inner{
String str2 = "内部类";
}
}

局部内部类

局部内部类与局部变量一样,不能使用访问控制修饰符和static修饰符,局部内部类仅在当前方法中有效。

1
2
3
4
5
public class Outer {
public void test(){
class Inner{}//内部类
}
}

匿名内部类

这种类我们之前有所使用,我们来举一个例子,应该会很清楚。总所周知接口是不能实例化的,而这个例子却可以。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Demo {
public static void main(String[] args) {
new test(){//实际上这里的效果跟test test = new test()相同
@Override
public void say() {
System.out.println("hello world!");
}
};
}
}
interface test{
void say();
}