面向对象特征
面向对象三大特征: 集成, 封装, 多态
继承
继承: - 子类可以从父类继承属性和方法
- 对外公开某些属性和方法
要点(eclipse 中 Ctrl+T 查看继承结构)
1. 父类也称超类, 基类, 派生类
2.Java 中只有单继承, 没有 C++ 那种多继承
3. 接口有多继承
4. 子类继承父类, 可以得到父类的全部属性和方法(除了构造方法), 但不一定可以直接访问(例如父类中的私有属性和方法) 5. 如果定义一个类时, 没有调用 extends, 则它的父类是 java.lang.object
Object 类是所有 Java 类的根基类, 也就意味着所有的 Java 对象都有 object 类的属性和方法
关键字 super
super 是直接父类对象的引用, 可以通过 super 来访问父类中被子类覆盖的方法或属性
属性 / 方法查找顺序(如变量 h)
1. 查找当前类中有没有属性 h
2. 依次上溯每个类的父类, 查看每个父类中有没有 j, 直到 object
3. 如果没有找到, 则出现编译错误
4. 上述步骤中, 只要找到变量 h, 则这个过程终止
构造方法调用顺序
构造方法第一句总是 super(...)来调用父类对应的构造方法. 所以流程是先向上追溯到 object, 然后再依次向下执行类的初始化和构造方法, 直到当前子类为止, 同静态初始化块一样, 先把静态初始化全部执行 (父类直至 object 和子类) 完后, 再执行构造方法
封装
封装作用 - 对外隐藏某些属性和方法
- 对外公开某些属性和方法
修饰符 | 同一个类 | 同一个包 | 不同包的子类 | 所有类 |
private | * | |||
defualt | * | * | ||
proteced | * | * | * | |
public | * | * | * | * |
成员 (成员变量或成员方法) 访问权限共四种:
private
只能被这个类本身访问
default
可以被这个类本身访问
可以被同一个包中的类访问
protected
可以被这个类分数访问
可以被同一个包中的所有其他类访问
被它的子类 (同一个包以及不同包的子类) 访问
public
可以被该项目的所有包中的所有类访问
类的访问权限共两种:
public
可以被同一项目中所有的类访问(必须与文件名同名)
default
可以被同一个包的类访问
封装要点:
类的属性的处理
一般使用 private 访问权限
提供相应的 get/set 方法来访问相关属性, 这些方法通常用 public 修饰, 以提供对属性的赋值与读取操作(boolean 变量的 get 方法是以 is 开头)
一些只用于本类的辅助性方法可以用 private 修饰
希望其他类调用的方法用 public 修饰
重写
子类通过重写父类的方法, 可以用自身的行为替换父类的行为
重写的三个要点:
"==" : 方法名, 形参列表, 返回值类型相同
"<=" : 返回值类型和声明异常类型, 子类小于等于父类
">=" : 访问权限, 子类大于等于父类. 重写的方法不能使用比被重写方法更严格的访问权限
- public class TestOverride {
- public static void main(String[] args) {
- Vehicle v1 = new Vehicle();
- Vehicle v2 = new Horse();
- Vehicle v3 = new Plane();
- v1.run();
- v2.run();
- v3.run();
- v1.stop();
- v2.stop();
- v3.stop();
- }
- }
- class Vehicle {
- public void run() {
- System.out.println("跑.....");
- }
- public void stop() {
- System.out.println("停止不动");
- }
- }
- class Horse extends Vehicle {
- public void run() {
- System.out.println("嘚嘚......");
- }
- }
- class Plane extends Vehicle {
- public void run() {
- System.out.println("咻......");
- }
- public void stop() {
- System.out.println("根本停不下来");
- super.stop(); // 通过 super 调用父类 Vehicle 中被覆盖的 stop 函数
- }
- }
- /* 执行结果
- 跑.....
- 嘚嘚......
- 咻......
- 停止不动
- 停止不动
- 根本停不下来
- 停止不动
- */
多态
多态: 指同一个方法调用, 由于对象的不同, 可能会有不同的行为, 适应多种变化, 使得代码变得更加通用
属性没有多态
引用变量的两种类型:
编译时类型(模糊一点, 一般是一个父类)
由声明时类型决定
运行时类型(运行时, 具体是哪个子类就是哪个子类)
由实际对应的对象类型决定
多态要点:
1. 多态是方法的多态, 不是属性的多态(多态与属性无关)
2. 多态的存在要有 3 个必要条件: 继承, 方法重写, 父类引用指向子类对象
3. 父类引用指向子类对象后, 用该父类引用调用子类重写的方法, 此时实现多态
对象的转型
父类引用指向子类对象, 称这个过程为向上转型, 属于自动类型转换, 向上转型后的父类引用变量只能调用它编译类型的方法, 不能调用它运行时的方法. 这时需要进行类型的强制转换, 称之为向下转型, 在向下转型过程中, 必须将引用变量转换成真实的子类类型(运行时类型), 否则会出现转换异常 ClassCastException
子类转换为父类: 自动转换 - 上转型对象不能操作子类新增的成员变量和方法
- 上转型对象可以操作子类继承或重写的成员变量和方法 - 如果子类重写了父类的某个方法, 上转型对象调用该方法时, 是调用的重写方法
父类转换为子类: 强制转换
- public class TestPolym {
- public static void main(String[] args) {
- Animal animal = new Dog(); // 向上类型转换
- // 属性没有多态!!!
- System.out.println(animal.age); // 属性调用时, 仍然是基类属性, 属性没有多态
- animal.shout(); // 调用 Dog 类中的 shout 函数
- animalCry(animal);
- // 传的具体是哪一个类就调用哪一个类的方法, 大大提高了程序的可扩展性
- // 如果没有多态, 这里需要写很多重载方法, 如果增加一种动物, 就需要重载一种动物的叫法, 非常麻烦
- animalCry(new Dog());
- // 有了多态后, 只需要增加这个类继承 Animal 基类就可以了
- animalCry(new Dog());
- // 编写程序时, 如果想调用运行时类的方法, 只能进行类型转换, 不然通不过编译器检查
- Dog dog = (Dog) animal;
- dog.gnawBone();
- System.out.println(dog instanceof Animal);
- System.out.println(animal instanceof Cat);
- System.out.println(animal instanceof Dog);
- Dog d = new Dog();
- animalCry(d);
- }
- static void animalCry(Animal a)
- {
- a.shout();
- }
- /*********** 没有多态时需重写下面两个重载方法 **************
- static void animalCry(Dog a)
- {
- a.shout();
- }
- static void animalCry(Cat a)
- {
- a.shout();
- }
- ***********************************************************/
- }
- class Animal {
- int age = 10;
- public void shout() {
- System.out.println("叫了一声");
- }
- }
- class Dog extends Animal {
- int age = 28;
- public void shout() {
- System.out.println("旺旺");
- }
- public void gnawBone() {
- System.out.println("在啃骨头");
- }
- }
- class Cat extends Animal {
- int age = 18;
- public void shout() {
- System.out.println("喵喵");
- }
- }
- /*
- 10
- 旺旺
- 旺旺
- 旺旺
- 旺旺
- 在啃骨头
- */
抽象类
抽象类是一种模板, 为所有子类提供一个通用模板, 子类可以在这个模板基础上进行扩展
通过抽象类可以避免子类设计的随意性, 这样就可以做到严格限制子类的设计, 使子类之间更加通用
要点:
抽象方法和抽象类都必须使用 abstract 来修饰
抽象方法没有方法体, 只需要声明不需要实现
抽象方法的类只能定义抽象类
相反, 抽象类里的方法不一定全是抽象方法, 也可以没有抽象方法
抽象类可以包含属性, 方法, 构造方法
抽象类不能实例化, 及不能用 new 来实例化抽象类, 只能用来被子类调用
抽象类只能用来继承
抽象方法必须被子类实现, 抽象类的子类必须覆盖所有的抽象方法才能被实例化, 否则还是抽象类
接口
接口与类的区别:
接口是比 "抽象类" 还抽象的 "抽象类", 可以更加规范的对子类进行约束. 全面的专业的石祥路: 规范和具体实现的分离 接口就是规范, 定义的是一组规则, 体现了现实世界中 "如果能..., 则必须..." 的意思 接口的本质是契约, 定制好后大家都需遵守 项目的具体需求是多变的, 必须以不变应万变才能从容开发, 此处的 "不变" 就是 "规范"
接口相关规则:
接口中所有方法都是抽象的
即使没有显式的将接口中的成员用 public 标示, 也是 public 访问类型
接口中变量默认用 public static final 标示, 所有接口中定义的变量就是全局静态常量
接口中方法默认用 public abstract 表示
可以定义一个新接口, 用 extends 区继承一个已有的接口
可以定义一个类, 用 implements 去实现一个接口中所有方法
可以定义一个抽象类, 用 implements 去实现一个接口中部分方法
格式: [访问修饰符] interface 接口名 [extends 父接口 1, 父接口 2, ...] { 常量定义 // 总是: public static final 方法定义 // 总是: public abstract }
接口的实现
子类通过 implements 来实现接口中的规范
接口不能创建实例, 但是可以用于声明引用变量类型
一个类实现了接口, 必须事项接口中所有的方法, 并且这些方法只能是 p ublic
Java 的类只支持单继承, 接口支持多继承
内部类
内部类: 将一个类定义置入另一个类定义中
类中定义的内部类特点 内部类作为外部类的成员, 可以直接访问外部类的成员(包括 private 成员), 反之则不行
内部类作为外部类成员, 可以声明为 private, 默认, protected, public
内部类成员只有在内部类的方位之内是有效的
用内部类定义在外部类中不可访问的属性. 这样就在外部类中实现了比外部类 private 还要小的访问权限
编译后生成两个类: OuterClass.class 和 OuterClass$InnerClass.class
内部类分类有: 成员内部类, 静态内部类, 方法内部类, 匿名内部类
匿名内部类:
可以实现一个接口, 或者继承一个父类 只能实现一个借口
适合创建那种只需要一次使用的类, 不能重复使用. 比较常见的是在图形界面 GUI 里用得到 匿名内部类要使用外部类的局部变量, 必须使用 final 修饰该局部变量
来源: http://www.bubuko.com/infodetail-2778553.html