面向对象

  1. 1. 面向对象的特征
  2. 2. 抽象类与接口
  3. 3. 内部类
  4. 4. 重载与重写
  5. 5. hashCode()和equals()方法的联系
  6. 6. final, finally, finalize的区别
  7. 7. Comparable和Comparator接口的作用以及区别
  8. 8. Java是否支持多继承
  9. 9. extends 和super 泛型限定符
  10. 10. 什么是泛型

面向对象的特征

  1. java面向对象的三大特征是什么?
    封装、继承、多态。
  2. 封装
    把属性和方法隐藏起来,只保留一些对外的接口和外部进行交互。
  3. 继承
    子类继承父类的特征和行为,使得子类具有父类的非private属性和方法。
  4. 多态
    多态就是同一个接口,使用不同的实现,而执行不同的操作。
  5. 抽象
    将一类对象的共同特征总结出来构造类的过程,数据抽象指的是属性,行为抽象指的是方法。

抽象类与接口

  1. 抽象类

​ 1)抽象类是用来捕捉子类的通用特性的

​ 2)它不能被实例化,只能被用作子类的超类

​ 3)抽象类是被用来创建继承层级里子类的模板

  1. 接口

​ 1)接口是抽象方法的集合

​ 2)如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法

​ 3)如果实现了这个接口,那么就必须确保使用这些方法

​ 4)接口只是一种形式,接口自身不能做任何事情

  1. 抽象类和接口的对比
参数 抽象类 接口
默认的方法实现 它可以有默认的方法实现 接口完全是抽象的。它根本不存在方法的实现
实现 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现
构造器 抽象类可以有构造器 接口不能有构造器
与正常Java类的区别 除了你不能实例化抽象类之外,它和普通Java类没有任何区别 接口是完全不同的类型
访问修饰符 抽象方法可以有publicprotecteddefault这些修饰符 接口方法默认修饰符是public。你不可以使用其它修饰符。
main方法 抽象方法可以有main方法并且我们可以运行 接口没有main方法,因此我们不能运行它
多继承 抽象方法可以继承一个类和实现多个接口 接口只可以继承一个或多个其它接口
速度 它比接口速度要快 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
添加新方法 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 如果你往接口中添加方法,那么你必须改变实现该接口的类。

内部类

  1. 概述

​ 1)把类定义在另一个类的内部,该类就被称为内部类

​ 2)把类Inner定义在类Outer中,类Inner就被称为内部类

  1. 访问规则

​ 1)可以直接访问外部类的成员,包括私有

​ 2)外部类要想访问内部类成员,必须创建对象

  1. 分类

​ 1)成员内部类:位于外部类成员位置的类,可以使用外部类中所有的成员变量和成员方法(包括private的)

​ 2)局部内部类:定义在一个方法或者一个作用域里面的类,主要是作用域发生了变化,只能在自身所在方法和属性中被使用

​ 3)静态内部类:用static修饰的内部类,不能使用外部类的非static成员变量和成员方法

​ 4)匿名内部类:一个没有名字的类,是内部类的简化写法,其实是继承该类或者实现接口的子类匿名对象

重载与重写

  1. 方法重载

​ 1)同一个类中的多个方法具有相同的名字,这些方法具有不同的参数列表

​ 2)参数类型和个数不一样,返回值类型可以相同也可以不相同

​ 3)无法以返回型别作为重载函数的区分标准

​ 4)重载Overloading是一个类中多态性的一种表现。

  1. 方法重写

​ 1)子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型

​ 2)子类中不能重写父类中的final方法

​ 3)子类中必须重写父类中的abstract方法

hashCode()和equals()方法的联系

  1. 相等(相同)的对象必须具有相等的哈希码(或者散列码)。

  2. 如果两个对象的hashCode相同,它们并不一定相同。

final, finally, finalize的区别

  1. final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
  2. finally是异常处理语句结构的一部分,表示总是执行。
  3. finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。

Comparable和Comparator接口的作用以及区别

  1. Comparable接口包含compareTo()方法。这个方法可以个给两个对象排序。
  2. Comparator接口包含compare()和equals()方法。
  3. compare()方法用来给两个输入参数排序,返回负数,0,正数表明第一个参数是小于,等于,大于第二个参数。
  4. equals()方法需要一个对象作为参数,它用来决定输入参数是否和comparator相等。
  5. 只有当输入参数也是一个comparator并且输入参数和当前comparator的排序结果是相同的时候,这个方法才返回true。

Java是否支持多继承

  1. Java中类不支持多继承,只支持单继承(即一个类只有一个父类)。
  2. 但是java中的接口支持多继承,,即一个子接口可以有多个父接口。
  3. 接口的作用是用来扩展对象的功能,一个子接口继承多个父接口,说明子接口扩展了多个功能。
  4. 当类实现接口时,类就扩展了相应的功能。

extends 和super 泛型限定符

  1. 泛型中上界和下界的定义

​ 1)上界<? extend Fruit>

​ 2)下界<? super Apple>

  1. 上界和下界的特点

​ 1)上界的list只能get,不能add(确切地说不能add出除null之外的对象,包括Object)

​ 3)下界的list只能add,不能get

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
import java.util.ArrayList;
import java.util.List;

class Fruit {}
class Apple extends Fruit {}
class Jonathan extends Apple {}
class Orange extends Fruit {}

public class CovariantArrays {
public static void main(String[] args) {
//上界
List<? extends Fruit> flistTop = new ArrayList<Apple>();
flistTop.add(null);
//add Fruit对象会报错
//flist.add(new Fruit());
Fruit fruit1 = flistTop.get(0);

//下界
List<? super Apple> flistBottem = new ArrayList<Apple>();
flistBottem.add(new Apple());
flistBottem.add(new Jonathan());
//get Apple对象会报错
//Apple apple = flistBottem.get(0);
}
}
  1. 上界<? extend Fruit> ,表示所有继承Fruit的子类,但是具体是哪个子类,无法确定,所以调用add的时候,要add什么类型,谁也不知道。但是get的时候,不管是什么子类,不管追溯多少辈,肯定有个父类是Fruit,所以,我都可以用最大的父类Fruit接着,也就是把所有的子类向上转型为Fruit。
  2. 下界<? super Apple>,表示Apple的所有父类,包括Fruit,一直可以追溯到老祖宗Object 。那么当我add的时候,我不能add Apple的父类,因为不能确定List里面存放的到底是哪个父类。但是我可以add Apple及其子类。因为不管我的子类是什么类型,它都可以向上转型为Apple及其所有的父类甚至转型为Object 。但是当我get的时候,Apple的父类这么多,我用什么接着呢,除了Object,其他的都接不住。

什么是泛型

  1. 泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
  2. 顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class GenericTest {

public static void main(String[] args) {
/*
List list = new ArrayList();
list.add("qqyumidi");
list.add("corn");
list.add(100);
*/

List<String> list = new ArrayList<String>();
list.add("qqyumidi");
list.add("corn");
//list.add(100); // 1 提示编译错误

for (int i = 0; i < list.size(); i++) {
String name = list.get(i); // 2
System.out.println("name:" + name);
}
}
}
  1. 采用泛型写法后,在//1处想加入一个Integer类型的对象时会出现编译错误,通过List,直接限定了list集合中只能含有String类型的元素,从而在//2处无须进行强制类型转换,因为此时,集合能够记住元素的类型信息,编译器已经能够确认它是String类型了。