一.面向对象
-
需要记住的知识点
-
面向对象的特征
-
继承
- java只支持单继承,不支持多继承,但是可以形成继承体系
- 接口倒是可以继承(实现)多个。
-
子类继承父类,在子类初始化时,会先调用父类的初始化,否则子类是无法使用父类的方法和成员变量的;
- 默认子类调用父类的无参构造。如果父类显式声明了有参构造,系统不会默认生成父类的无参构造,因此子类默认调用父类的无参构造也就无从说起,编译时报错。此时需要使用super.父类已有构造 来实现父类的初始化
- 成员方法和成员变量的调用遵循就近原则,如果子类和父类存在同名的成员变量和方法,子类会优先使用本类的成员变量和方法。如果想调用同名的父类方法和成员变量,就必须使用supper关键字,来显式的表示这是父类的。
- 如果子类中的方法名与父类中的方法名同名,就叫方法重写(override)。方法重载(overload)是多态的表现。
- 多态
-
封装
- 使用this关键字,表示当前对象。this.成员变量 表示当前对象的成员变量。this.成员方法 表示当前对象的成员方法。
- 详见后续封装介绍:接口与抽象类
-
所谓的重构,就是不断抽象的过程
-
-
对象的构成
-
构造器
-
构造代码块
- 构造代码块是所有构造函数同类型的抽象,每调用一次构造函数,都会在构造函数的第一行执行构造代码块。
- 构造代码块是没有static关键字修饰的,但是静态代码块有。
- 静态代码块是随着类的加载而加载的,主要对类初始化。构造代码块是对象的初始化,每创建一个对象都会先执行构造代码块。构造方法是用来创建对象的。创建对象时,先调用构造方法,然后构造代码块是构造方法中第一个执行的命令。
-
代码示例
-
创建对象
1 package oop; 2 3 /** 4 * 测试构造代码块 5 */ 6 public class CodeBlock { 7 private String name; 8 private int age; 9 10 public CodeBlock(String name, int age) { 11 this.name = name; 12 this.age = age; 13 System.out.println("我在执行有参构造。"); 14 } 15 16 public CodeBlock() { 17 System.out.println("我在执行无参构造。"); 18 } 19 20 // 构造代码块 21 { 22 this.name="huabingood"; 23 this.age=18; 24 System.out.println("执行到了构造代码块。"); 25 } 26 27 @Override 28 public String toString() { 29 return "CodeBlock{" + 30 "name='" + name + '\'' + 31 ", age=" + age + 32 '}'; 33 } 34 }
-
测试
-
1 package oopTest; 2 3 import oop.CodeBlock; 4 import org.junit.Test; 5 6 public class CodeBlockTest { 7 @Test 8 public void test(){ 9 CodeBlock codeBlock = new CodeBlock(); 10 System.out.println(codeBlock.toString()); 11 } 12 @Test 13 public void test1(){ 14 CodeBlock codeBlock = new CodeBlock("华彬",22); 15 System.out.println(codeBlock.toString()); 16 } 17 }
-
-
-
成员变量
- 类的变量会初始化,但是方法的变量并不会初始化。
- 成员方法
-
-
static是随着类的加载而加载的,优先于对象而存在,被该类的所有对象共享;可以通过类名(对象名)调用(不用new对象就可以直接使用,当然使用new出来的对象调用也是可以的);静态的都在方法去,因此不需要new即可调用;静态修饰的不能访问this关键字,静态方法只能访问静态成员变量,因为他是随着类的加载而加载的。
- 静态方法只能访问静态成员变量,不能访问非静态成员变量,因为对象没有实例化的时候,非静态成员变量没有到堆内存中,但是静态成员变量已经在方法区了。先存在的不能调用不存在的东西。
- 同样的道理,静态方法只能调用静态的方法,不能调用非静态的成员方法。但是非静态方法既能调用静态的方法也能调用非静态的成员方法
-
final关键字
- 修饰方法则该方法不能被override
- 修饰成员变量只能被赋值一次,赋值之后不能被更改
- 修饰类则该类不能被继承
- final修饰引用类型,表示引用类型的地址不能变。就比如教室是不会变的,但是学生可以改变
-
-
类的初始化与实例化(这里的理解需要JVM知识)
- 一个对象可以被使用之前,必须被正确的初始化。在实例化一个对象时,JVM会检查相关类型是否已经加载并初始化。如果没有,JVM立即进行加载并调用类构造器完成类的初始化。初始化完成之后才会对类进行实例化
-
对象创建过程
- 实例变量初始化
- 实例代码块初始化
- 构造函数初始化
-
如果存在继承
- 父类的成员变量,父类的实例代码块,父类构造,子类成员变量,子类代码块,子类构造函数 的过程。
-
接口与抽象类
-
接口
-
是什么
- 是一种规范。只说明应该做什么,但是并不规定如何做。这意味着接口里通常定义一组公用方法
- 接口只有方法名没有方法体,实现接口就是让其既有方法名又有方法体。
- 体现了规范和实现分离的设计哲学,降低了模块之间的耦合
-
和其他的对比
- 从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。接口只能定义一系列方法,算是定义行为,而不能包含具体的变量,不能拥有自己的属性,但是抽象类能够拥有变量。
-
怎么用
-
注意要点
- 接口无法被实例化,不能new一个对象,但是可以使用多态来接具体实现子类
- 接口的方法默认使用public修饰,且只能是public abstract修饰(因为是默认的可以省略),所有方法不能有方法体。但是抽象类是可以有非抽象方法的。
- 接口中的实例变量默认是final,且只能是public static final 修饰(因为是默认的可以省略),但是抽象类中不一定。
- 一个类实现接口的话就要实现接口的所有方法(抽象类不必实现所有的方法,但是具体实现子类必须实现所有的方法),而抽象类不一定?
- 接口是多个类的公共行为规范,接口里的所有成员,常量,方法,内部类都必须是public修饰。但是不能有构造器和初始化代码块。因为不能实例化,所以具体实现子类若想调用父接口的成员变量,就只能调用静态的成员变量。
-
通用设置
[修饰符] interface 接口名 [extends 父接口1,父接口2…]{
零到多个的常量定义…
零到多个的抽象方法顶底…零到多个内部类,接口,枚举定义…
零到多个默认方法或类定义…
}
-
-
-
抽象类
-
是什么
抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用作子类的超类。抽象类是被用来创建继承层级里子类的模板
-
- 抽象类和接口的异同
-
抽象类 |
接口 |
对类的抽象 |
对行为的抽象 |
主要是模块内部的抽象 |
主要是模块之间的联系 |
自下而上的设计,需要在重构中抽取 |
自上而下,只需定义规则 |
子类继承必须实现所有的抽象方法 |
子类实现可以实现部分抽象方法,但是在一个继承体系内实现万所有的方法 |
使用abstrict关键字修饰接口 |
使用interface关键字修饰抽象类 |
默认是public修饰类 |
默认是public abstrice修饰类,可以省略 |
成员变量是public,protected 的 |
成员变量public static final,可以省略 |
可以有抽象方法,抽象方法不能有实现。可以有普通方法。 |
只能是public abstrict修饰的没有实现的抽象方法。(java8中存在静态方法) |
类是单继承 |
接口是多继承 |
不能被实例化,但是可以有构造,有成员变量,方便子类调用父类的方法和成员变量。 |
不能被实例化,没有构造。 |
往抽象类中添加新方法,可以给出默认实现,不需修改已经存在的类 |
JDK8可以使用default给出默认实现,实现类可以不实现这个方法 |
-
具体案例代码
1 package oop.amimailDemo; 2 /** 3 * 描述: 4 * 这个抽象类主要定义动物的抽象行为 5 * 6 * @author huabingood@qq.com 7 * @version 1.0 8 * @create 2018-09-06 9 */ 10 public interface AnimalActive { 11 // 接口成员变量默认是public static final 修饰 12 int hige = 10; 13 14 // 抽象方法默认是public abstract 修饰 15 void eat(AnimalImple animalImple); 16 17 void sleep(); 18 19 void jump(AnimalImple animalImple); 20 } 21 22 package oop.amimailDemo; 23 24 /** 25 * 描述: 26 * 这个是抽象类,实现了接口的部分方法,并定义一个抽象方法,给孩子 27 * 28 * @author huabingood@qq.com 29 * @version 1.0 30 * @create 2018-09-06 31 */ 32 public abstract class AnimalImple implements AnimalActive { 33 private String name; 34 private int age; 35 36 public AnimalImple() { 37 } 38 39 public AnimalImple(String name, int age) { 40 this.name = name; 41 this.age = age; 42 } 43 44 public String getName() { 45 return name; 46 } 47 48 public void setName(String name) { 49 this.name = name; 50 } 51 52 public int getAge() { 53 return age; 54 } 55 56 public void setAge(int age) { 57 this.age = age; 58 } 59 60 @Override 61 public void eat(AnimalImple animalImple) { 62 System.out.println(animalImple.getName() + "正在吃饭。"); 63 } 64 65 @Override 66 public void sleep() { 67 System.out.println(this.getName() + "正在睡觉"); 68 } 69 70 } 71 72 package oop.amimailDemo; 73 74 /** 75 * 描述: 76 * 77 * @author huabingood@qq.com 78 * @version 1.0 79 * @create 2018-09-06 80 */ 81 public class Cat extends AnimalImple { 82 public Cat() { 83 } 84 85 // 调用构造时,调用父类的构造,不再调用默认的父类构造 86 public Cat(String name, int age) { 87 super(name, age); 88 } 89 90 @Override 91 public void jump(AnimalImple animalImple) { 92 System.out.println(animalImple.getName() + "年龄是:" + animalImple.getAge() + "。能跳:" + AnimalActive.hige); 93 } 94 95 public void myOnly() { 96 System.out.println("这是猫独有的方法"); 97 } 98 }