抽象类

什么是抽象类

被abstract修饰的类就是抽象类。抽象类是类的进一步抽象,抽象类中的方法可以不做具体的实现(抽象方法,由abstract修饰)。抽象类中也可以有普通方法。

抽象方法不能由static和final修饰,因为抽象方法要被子类重写。

抽象类中不一定要有抽象方法,但是有抽象方法的类一定是抽象类。

抽象类不能实例化,但可以引用其子类对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
abstract class Animal {
public String name;
//抽象类中也可以有构造方法,也可以有普通方法、属性
public Animal(String name) {
this.name = name;
}

//抽象方法,不做具体实现
public abstract void eat();
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}

@Override
public void eat() {
System.out.println(this.name+"正在吃狗粮");
}
}
public class Demo1 {

public static void main(String[] args) {
//抽象类不能实例化,但可以引用其子类对象。
Animal animal = new Dog("旺旺");
//子类重写eat方法
animal.eat();
}

}

执行结果:旺旺正在吃狗粮

为什么需要抽象类

抽象类中的方法可以不做具体实现,为了子类能够继承该抽象类。使用抽象类能够多一层编译器校验,增加了安全性。就像常量用final修饰,不小心修改时编译器会报错提醒。

像上面的代码main方法中new Dog改成new Animal,编译器就会报错:‘Animal’ is abstract; cannot be instantiated。

接口

什么是接口

接口是多个类的公共规范,是一种引用数据类型。接口可以理解为一种功能、特性,类实现某个接口,便可以具备某种功能。

接口中的方法默认是由public abstract修饰,接口中的属性默认是public final static。建议接口中的方法和属性不加任何修饰符号, 保持代码的简洁性.

接口不能实例化。

接口中不能有静态代码块和构造方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
interface Running{
void run(); //方法不加修饰符,默认为public abstract void run()
}
interface Flying{
void fly();
}
abstract class Animal {
public String name;
//抽象类中也可以有构造方法
public Animal(String name) {
this.name = name;
}

//抽象方法,不做具体实现
public abstract void eat();
}
class Dog extends Animal implements Running {
public Dog(String name) {
super(name);
}

@Override
public void eat() {
System.out.println(this.name+"正在吃狗粮");
}
//实现接口中的run方法,必须为public,因为接口中的run方法是public,重写时要分配更高的访问权限

@Override
public void run() {
System.out.println(this.name+"正在扑向他的主人");
}
}

class Bird extends Animal implements Flying{
//继承父类,需要重写父类的构造方法
public Bird(String name) {
super(name);
}
//重写父类的抽象方法
@Override
public void eat() {
System.out.println(this.name+"正在觅食");
}

//实现接口,必须实现接口的抽象方法,否则类需设置为抽象类
@Override
public void fly() {
System.out.println(this.name+"正在天空中自由地翱翔");
}
}
public class Demo1 {

public static void main(String[] args) {

Dog dog = new Dog("旺旺");
dog.eat();
dog.run();
Bird bird = new Bird("飞儿");
bird.eat();
bird.fly();

}
}

执行结果:

旺旺正在吃狗粮
旺旺正在扑向他的主人
飞儿正在觅食
飞儿正在天空中自由地翱翔

为什么需要接口

Java不允许多重继承,通过接口可以提供多重继承的大部分好处,同时还能避免多重继承的复杂性和低效性。

接口的使用实例

Comparable接口

对数组元素按年龄排序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.Arrays;

class Student implements Comparable<Student> {

public String name;
public int age;

public Student(String name, int age) {
this.name = name;
this.age = age;
}

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写compareTo方法
@Override
public int compareTo(Student o) {

// if(this.age>o.age){
// return 1;
// }else if(this.age<o.age){
// return -1;
// }else {
// return 0;
// }
return this.age-o.age;
}
}
public class Compare {

public static void main(String[] args) {
Student[] students = new Student[]{
new Student("panghu",20),
new Student("xiaofu",18),
new Student("daxiong",19),
new Student("jingxiang",16)
};

Arrays.sort(students);
System.out.println(Arrays.toString(students));
}
}

执行结果:

[Student{name=‘jingxiang’, age=16}, Student{name=‘xiaofu’, age=18}, Student{name=‘daxiong’, age=19}, Student{name=‘panghu’, age=20}]

上面代码有一个问题,只能按年龄排序,如果想按姓名排序就要修改compareTo方法,修改后又只能按姓名排序。有没有一种办法,可以实现按不同的属性进行排序。利用比较器可以实现该要求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.util.Arrays;
import java.util.Comparator;

class Student1 {

public String name;
public int age;

public Student1(String name, int age) {
this.name = name;
this.age = age;
}

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}

}
class AgeComparator implements Comparator<Student1> {

@Override
public int compare(Student1 o1, Student1 o2) {
return o1.age-o2.age;
}
}

class NameComparator implements Comparator<Student1> {

@Override
public int compare(Student1 o1, Student1 o2) {
return o1.name.compareTo(o2.name);
}
}
public class Compare1 {

public static void main(String[] args) {
Student1[] students = new Student1[]{
new Student1("panghu",20),
new Student1("xiaofu",18),
new Student1("daxiong",19),
new Student1("jingxiang",16)
};
AgeComparator ageComparator = new AgeComparator();
NameComparator nameComparator = new NameComparator();
//按年龄排序
Arrays.sort(students,ageComparator);
System.out.println("按年龄"+Arrays.toString(students));
//按姓名排序
Arrays.sort(students,nameComparator);
System.out.println("按姓名"+Arrays.toString(students));
}
}

执行结果:

按年龄[Student{name=‘jingxiang’, age=16}, Student{name=‘xiaofu’, age=18}, Student{name=‘daxiong’, age=19}, Student{name=‘panghu’, age=20}]
按姓名[Student{name=‘daxiong’, age=19}, Student{name=‘jingxiang’, age=16}, Student{name=‘panghu’, age=20}, Student{name=‘xiaofu’, age=18}]

Clonable接口

实现Clonable接口需要重写Object类的clone()方法,在方法中使用super关键字调用Object类的clone()方法,然后调用该方法即可实现克隆。

  • 浅拷贝:仅仅拷贝当前对象本身,不拷贝引用类型。
    浅拷贝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Phone{
public String phone;

}
class Person implements Cloneable{
public int age;
Phone p = new Phone();

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}


@Override
public String toString() {
return "Person{" +
"age=" + age +
", p.phone=" + p.phone +
'}';
}
}
public class Demo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
person.age=20;
person.p.phone="xiaomi";
Person person2 = (Person)person.clone();
person2.age=10;
person2.p.phone="iphone";
System.out.println(person);
System.out.println(person2);
}

}
//运行结果:
//Person{age=20, p.phone=iphone}
//Person{age=10, p.phone=iphone}
  • 深拷贝:不仅拷贝当前对象,还拷贝其引用类型。

    深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Phone implements Cloneable{
public String phone;

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public int age;
Phone p = new Phone();

@Override
protected Object clone() throws CloneNotSupportedException {
Person tmp = (Person) super.clone();
tmp.p= (Phone) this.p.clone();
return tmp;
}


@Override
public String toString() {
return "Person{" +
"age=" + age +
", p.phone=" + p.phone +
'}';
}
}
public class Demo1 {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
person.age=20;

person.p.phone="xiaomi";
Person person2 = (Person)person.clone();
person2.age=10;

person2.p.phone="iphone";
System.out.println(person);
System.out.println(person2);
}

}
//运行结果:
//Person{age=20, p.phone=xiaomi}
//Person{age=10, p.phone=iphone}