参考 pidai的全栈学习路线
思维导图参考(有点糊):
1.类
-
自定义类
格式:[访问修饰符] [修饰符] class 自定义类名 [extends 父类] [implement 接口1,接口2…]{ } -
内部类
内部类提供了一种实现类的嵌套和封装的机制- 内部类是定义在其他类内部的类。
- 内部类可以访问外部类的所有成员,包括私有成员。
- 内部类分为四种类型:成员内部类、静态内部类、局部内部类和匿名内部类。
- 内部类可以实现面向对象设计的一些模式,如事件监听器、迭代器等。
-
抽象类
抽象类提供了一种定义子类的模板和规范的机制- 抽象类是不能被实例化的类,它用于定义子类的结构和行为。
- 抽象类中可以包含抽象方法和非抽象方法。
- 抽象方法是没有方法体的方法,必须在子类中实现。
- 子类继承抽象类时,必须要实现抽象类中的所有抽象方法,除非子类也是抽象类。
-
接口
接口提供了一种定义公共行为和多重继承的机制- 接口是一种抽象数据类型,定义了一组方法的规范,而不包含方法的实现。
- 接口中的方法默认是公有的抽象方法,可以省略 public abstract 关键字。
- 类可以实现一个或多个接口,通过关键字
implements
。 - 接口之间可以通过关键字
extends
进行继承,一个接口可以继承多个接口。 - 接口提供了一种多重继承机制,可以帮助解决Java单继承的限制。
- 接口常用于定义不同类之间的共同行为,实现类可以根据需要选择实现哪些接口。
-
类的访问修饰符
- 顶级类
- public
- 默认
- 方法、属性、内部类
- public
- protected
- private
- 默认
- 顶级类
-
类与类的关系
- 泛化关系 (Generalization)
用来描述继承关系,在 Java 中使用
extends
关键字。
- 实现关系 (Realization)
用来实现一个接口,在 Java 中使用
implements
关键字。- 聚合关系 (Aggregation)
表示整体由部分组成,但是整体和部分不是强依赖的,整体不存在了部分还是会存在。
- 组合关系 (Composition)
和聚合不同,组合中整体和部分是强依赖的,整体不存在了部分也不存在了。比如公司和部门,公司没了部门就不存在了。但是公司和员工就属于聚合关系了,因为公司没了员工还在。
- 关联关系 (Association)
表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用 1 对 1、多对 1、多对多这种关联关系来表示。比如学生和学校就是一种关联关系,一个学校可以有很多学生,但是一个学生只属于一个学校,因此这是一种多对一的关系,在运行开始之前就可以确定
- 依赖关系 (Dependency)
和关联关系不同的是,依赖关系是在运行过程中起作用的。A 类和 B 类是依赖关系主要有三种形式:
- A 类是 B 类中的(某中方法的)局部变量;
- A 类是 B 类方法当中的一个参数;
- A 类向 B 类发送消息,从而影响 B 类发生变化;
2.对象
- 一切皆为对象
- 对象有方法和属性
- 对象都是唯一的
- 对象都是某个类的实例
3.方法
-
方法的声明格式:
[访问修饰符] [修饰符] 返回类型 方法名([参数列表]) throws [异常类型] { }
public static int add(int a, int b) throws ArithmeticException { // 方法体 return a + b; }
说明:方法名为
add
,接受两个参数a
和b
,返回类型为int
,可能抛出ArithmeticException
异常。- 访问修饰符
- public
- private
- protected
- 修饰符
- static
- abstract
- final
- synchronized
- native
- 访问修饰符
-
方法调用
- 静态方法:类名.方法名(实参列表);
- 非静态方法:对象.方法名(实参列表)
4.三大特性
4.1 封装
-
利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。用户无需知道对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
-
优点:
- 减少耦合: 可以独立地开发、测试、优化、使用、理解和修改
- 减轻维护的负担: 可以更容易被程序员理解,并且在调试的时候可以不影响其他模块
- 有效地调节性能: 可以通过剖析确定哪些模块影响了系统的性能
- 提高软件的可重用性
- 降低了构建大型系统的风险: 即使整个系统不可用,但是这些独立的模块却有可能是可用的
-
以下 Person 类封装 name、gender、age 等属性,外界只能通过 get() 方法获取一个 Person 对象的 name 属性和 gender 属性,而无法获取 age 属性,但是 age 属性可以供 work() 方法使用。
-
注意到 gender 属性使用 int 数据类型进行存储,封装使得用户注意不到这种实现细节。并且在需要修改 gender 属性使用的数据类型时,也可以在不影响客户端代码的情况下进行。
public class Person { private String name; private int gender; private int age; public String getName() { return name; } public String getGender() { return gender == 0 ? "man" : "woman"; } public void work() { if (18 <= age && age <= 50) { System.out.println(name + " is working very hard!"); } else { System.out.println(name + " can't work any more!"); } } }
4.2 继承
- 继承实现了 IS-A 关系,例如 Cat 和 Animal 就是一种 IS-A 关系,因此 Cat 可以继承自 Animal,从而获得 Animal 非 private 的属性和方法。
- 继承应该遵循里氏替换原则,子类对象必须能够替换掉所有父类对象。
- Cat 可以当做 Animal 来使用,也就是说可以使用 Animal 引用 Cat 对象。父类引用指向子类对象称为 向上转型 。
Animal animal = new Cat();
4.2.1 访问权限
访问修饰符 | 同一个类 | 同一个包 | 子类 | 任何地方 |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y | |
default | Y | Y | ||
pravite | Y |
- public
-
public修饰符表示公开的,公共的。不同类、不同包下都可以访问
-
1个java文件中只可以有一个public修饰的类,并且类名需要和文件名相同
-
- private
-
可用来修饰内部类、属性、方法
-
“私有的”,即被private修饰的属性、方法、类只能被该类的对象访问,其子类不能访问,更不能允许跨包访问
-
注意:private可以修饰内部类,不可以修饰外部类
class test{//private不能修饰外部类 private String name;//private修饰属性 private void test(){//private修饰方法 System.out.println("private修饰方法"); } private class innerClass{//private修饰内部类 } }
-
- protected
-
protected修饰符表示受保护的,它主要的作用是保护子类,子类可以用它修饰的成员,其他的不可以
-
protected修饰符可以被本类、同一个包中的类、不同包中的子类所访问到
-
protected可以修饰属性、方法,但是不能修饰外部类,可以修饰内部类
class test{//不能用protected修饰外部类 protected String name;//protected修饰属性 protected void demo(){//protected修饰方法 System.out.println("protected修饰方法"); } protected class innerClass{//protected修饰内部类 } }
-
- default 包级可见
4.2.2 抽象类与接口
- 抽象类
- 抽象类和抽象方法都使用 abstract 关键字进行声明。抽象类一般会包含抽象方法,抽象方法一定位于抽象类中。
- 抽象类和普通类最大的区别是,抽象类不能被实例化,需要继承抽象类才能实例化其子类。
- 接口
- 接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。
- 从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。
- 接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。
- 接口的字段默认都是 static 和 final 的。
- 对比:
- 目的:
- 抽象类用于表示“是一个”关系,它表达的是一种继承关系。
- 接口用于表示“能做什么”关系,它表达的是一种能力。
- 使用场景:
- 当多个类之间存在较多共享状态或行为时,使用抽象类更合适。
- 当多个类需要实现多个可选的行为时,接口更加适用。
- 扩展性:
- 抽象类在Java中限制了子类的扩展性,因为Java不允许多重继承。
- 接口提供了更好的扩展性,特别是在需要多个类实现同一个行为或多个行为时。
- 目的:
4.2.3 super关键字
- 访问父类的构造函数: 可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。
- 访问父类的成员: 如果子类重写了父类的中某个方法的实现,可以通过使用 super 关键字来引用父类的方法实现。
public class SuperExample {
protected int x;
protected int y;
public SuperExample(int x, int y) {
this.x = x;
this.y = y;
}
public void func() {
System.out.println("SuperExample.func()");
}
}
public class SuperExtendExample extends SuperExample {
private int z;
public SuperExtendExample(int x, int y, int z) {
super(x, y);
this.z = z;
}
@Override
public void func() {
super.func();
System.out.println("SuperExtendExample.func()");
}
}
SuperExample e = new SuperExtendExample(1, 2, 3);
e.func();
SuperExample.func()
SuperExtendExample.func()
4.2.4 重写和重载
-
重写:
- 存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。
- 为了满足里式替换原则,重写有以下两个限制:
- 子类方法的访问权限必须大于等于父类方法;
- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
- 使用
@Override
注解,可以让编译器帮忙检查是否满足上面的两个限制条件。
-
重载
-
存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。
-
应该注意的是,返回值不同,其它都相同不算是重载。
-
4.3 多态
-
多态分为编译时多态和运行时多态:
- 编译时多态主要指方法的重载
- 运行时多态指程序中定义的对象引用所指向的具体类型在运行期间才确定
-
运行时多态有三个条件:
- 继承
- 覆盖(重写)
- 向上转型
-
下面的代码中,乐器类(Instrument)有两个子类: Wind 和 Percussion,它们都覆盖了父类的 play() 方法,并且在 main() 方法中使用父类 Instrument 来引用 Wind 和 Percussion 对象。在 Instrument 引用调用 play() 方法时,会执行实际引用对象所在类的 play() 方法,而不是 Instrument 类的方法。
public class Instrument { public void play() { System.out.println("Instrument is playing..."); } } public class Wind extends Instrument { public void play() { System.out.println("Wind is playing..."); } } public class Percussion extends Instrument { public void play() { System.out.println("Percussion is playing..."); } } public class Music { public static void main(String[] args) { List<Instrument> instruments = new ArrayList<>(); instruments.add(new Wind()); instruments.add(new Percussion()); for(Instrument instrument : instruments) { instrument.play(); } } }
5.设计原则
- 单一职责原则
- 专业化
- 模块化
- 开闭环原则
- 对修改关闭
- 对扩展开放
- 抽象是关键
- 封装可变性
- 依赖倒转原则
- 里氏替换原则
- 接口隔离原则
- 合成聚合复用原则
- 迪米特法则
面试总结,非细致讲解,如有不足,欢迎指正