一、基础知识
1.访问权限修饰符
private friendly(默认) protected public 当前类访问权限 / / / / 包访问权限 x / / / 子类访问权限 x x / / 其他类访问权限 x x / /
二、面向对象的三大特性
1.封装:[合理隐藏,合理暴露]
- 何为封装?
封装指的是将客观事物抽象成类,把表示该事物属性的数据(成员变量)以及用于操作这些数据的方法(成员方法)都组合在一个类的内部,形成一个相对独立且完整的单元,对外隐藏类的内部实现细节,只通过特定的接口(通常是公共方法)来与外界交互。
- 设计规范?
合理隐藏,合理暴露。
- 如何控制对象的成员公开或隐藏?
公开成员,可以使用public关键字进行修饰。
隐藏成员,使用private关键字进行修饰。
总结:其实类就是一种封装,将要处理的数据和处理数据的方法结合为一个独立的整体,在封装的过程中,我们要清晰的认识到成员属性和成员方法的权限设置
例如,定义一个
Person
类,其中有age
属性,我们可以把age
设为私有(使用private
关键字修饰),外部类就不能直接访问这个属性了:public class Person { private int age; }
隐藏的目的:
提高安全性:防止外部代码随意修改对象内部的关键数据,避免数据被意外破坏或赋予不合理的值。比如上面
Person
类的age
属性,如果不隐藏直接对外暴露,外部代码可能会给age
赋一个负数等不合理的值。增强可维护性:类的内部实现细节(比如一些属性的存储方式、计算逻辑等)可以随时更改,只要对外提供的接口(方法)保持不变,使用该类的其他代码就不需要进行修改,降低了代码之间的耦合度。
实现方式:
使用访问修饰符:在 Java 中,通过
private
(私有,只能在本类中访问)、protected
(受保护,能在本类、同包的类以及子类中访问)等修饰符来控制成员(属性和方法)的可见性,从而达到隐藏内部细节的目的。例如,把类中的一些辅助属性设为private
,不让外部知晓和直接操作它们。暴露的目的:
提供必要功能:让外部代码能够使用类所具备的功能,完成相应的业务逻辑。比如
Person
类,外部可能需要获取这个人的年龄或者修改年龄(在合理的规则下),那就需要提供对应的 “获取年龄” 和 “设置年龄” 的方法供外部调用。实现交互协作:使得不同的类之间可以相互协作,共同构建复杂的软件系统。例如,一个
Order
类可能需要调用Person
类中获取姓名等信息的方法来完善订单相关的信息记录。实现方式:
通过公共方法暴露:对于需要对外提供访问的属性或功能,通常会定义公共的(使用
public
修饰符)方法。继续以Person
类为例,为了能让外部获取age
属性的值,我们可以提供一个public
的getAge
方法,如果想要在符合一定规则下修改年龄,可以定义setAge
方法:public class Person { private int age; public int getAge() { return age; } public int getAge() { return age; } public void setAge(int newAge) { if (newAge >= 0 && newAge <= 150) { // 简单的年龄合理性判断 age = newAge; } } }
2.继承
- 何为继承?
- Java中提供了一个关键字extends,用这个关键字,可以让一个类和另一个类建立起父子关系。
- 子类能继承什么?
- 子类能继承父类的非私有成员(成员变量、成员方法)
class Parent { public int publicVar; protected int protectedVar; private int privateVar; public void publicMethod() { System.out.println("这是父类的公共方法"); } protected void protectedMethod() { System.out.println("这是父类的受保护方法"); } private void privateMethod() { System.out.println("这是父类的私有方法"); } } class Child extends Parent { // 子类可以继承publicVar和publicMethod、protectedVar和protectedMethod // 但无法直接继承privateVar和privateMethod }
- 继承后对象的创建
- 子类的对象是由子类,父类共同完成。
2.1Java中类继承后的特点:
- Java是单继承的:一个类只能继承一个直接父类。
class A {} class B {} class C extends A, B {} // 在Java中这样写会报错,不允许一个类同时继承多个直接父类
- Java中的类不能多继承,但是可以多层继承。
class Grandparent { public int grandparentVar; public void grandparentMethod() { System.out.println("这是祖辈的方法"); } } class Parent extends Grandparent { public int parentVar; public void parentMethod() { System.out.println("这是父辈的方法"); } } class Child extends Parent { // 可以继承Parent类以及Grandparent类的非私有成员 }
- Java中Object类是Java中所有类的祖宗。
- Java中在子类方法中访问成员(成员变量、成员方法)采取就近原则,先找子类、再找父类、父类没有就报错。
class Parent { public int num = 10; } class Child extends Parent { public int num = 20; public void printNum() { System.out.println(num); // 这里会输出子类的num,即20,遵循就近原则 } }
- Java中子父类中出现重名的成员此时一定要在子类中使用父类的时可以用关键字---super.父类成员变量/父类成员方法。
class Parent { public int num = 10; public void showNum() { System.out.println("父类的num:" + num); } } class Child extends Parent { public int num = 20; public void showNum() { System.out.println("子类的num:" + num); super.showNum(); // 通过super调用父类的showNum方法 } }
2.2方法重写
- 当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法
class Animal { public void makeSound() { System.out.println("动物发出声音"); } } class Dog extends Animal { @Override public void makeSound() { System.out.println("汪汪汪"); } }
2.3子类构造器的特点
- 子类的全部构造器,都必须先调用父类的构造器,再执行自己的构造器。
- 为对象中包含父类这部分的成员变量进行赋值。
2.4this(....)调用兄弟构造器
- 在构造器中调用本类的其他构造器
- super(...)和this(...)必须写在构造器的第一行,而且两者不能同时出现。
3.多态[对象多态,行为多态]
何为多态?
- 多态是在继承/实现情况下的一种现象,表现为:对象多态,行为多态
class Animal { public void makeSound() { System.out.println("动物发出声音"); } } class Dog extends Animal { @Override public void makeSound() { System.out.println("汪汪汪"); } } class Cat extends Animal { @Override public void makeSound() { System.out.println("喵喵喵"); } } //当使用多态的形式时: Animal animal1 = new Dog(); Animal animal2 = new Cat(); animal1.makeSound(); // 输出 "汪汪汪",根据实际指向的Dog对象执行Dog类重写的方法 animal2.makeSound(); // 输出 "喵喵喵",根据实际指向的Cat对象执行Cat类重写的方法
多态前提
- 有继承/实现关系,存在父类引用子类对象,存在方法重写
多态注意事项
- 多态是对象,行为的多态,Java中的属性即成员变量不谈多态
class Parent { public int num = 10; } class Child extends Parent { public int num = 20; } Parent parent = new Child(); System.out.println(parent.num); // 输出 10,访问的是父类的num成员变量
3.1多态的好处
- 在多态形势下,右边对象是解耦合的,更便于扩展和维护
- 定义方法时,使用父类型的形参,可以接受一切子类对象,扩展性更强,更便利
- 存在问题
- 多态下不能使用子类的独有功能
- 解决方法
- 多态下的类型转换
- 自动类型转换:父类 变量名 = new 子类();
- 强制类型转换:子类 变量名 = (子类)父类变量名;
Animal animal = new Dog(); Dog dog = (Dog) animal; // 强制转换为Dog类型,就能调用Dog类独有的方法了,如dog.wagTail();
- 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错
- 运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException)的错误出来。
Animal animal = new Cat(); Dog dog = (Dog) animal; // 运行时会抛出ClassCastException异常,因为实际对象是Cat类型,无法转换为Dog类型
- 可以把对象转换成其真正的类型,从而解决了多态下不能调用子类独有方法的问题
- 强制转换建议
- 使用instanceof判断当前对象的真实类型。
Animal animal = new Dog(); if (animal instanceof Dog) { Dog dog = (Dog) animal; dog.wagTail(); }