写在前面的部分
Day8主要讲了final关键字的后续,多态,抽象类,接口,以及他们之间的联系.Day9主要讲了API文档的制作,和内部类的使用
笔记内容--面向对象
1.final
后续:
用final修饰引用数据类型,那么它不能在重新分配内存,但是可以改变成员变量的值
package Week04; public class TestDemo { public static void main(String[] args) { final Student s = new Student(); // s = new Student(); 报错因为被final修饰无法重新分配内存所以无法重新new一个对象 s.age = 10; // 并不会报错 } } class Student { int age; }
2.多态
a. 定义:
一个事物不同时刻呈现的不同状态b 前提:
(1)条件1:必须有继承关系(如果没有继承关系,谈不上多态!)
(2)条件2:必须有方法重写
子类出现了父类一样的 方法声明
(3)有父类引用指向子类对象:向上转型
Fu f = new Zi() ;
c. 多态的成员访问特点:
(1)成员变量: 编译看左边,执行看右边
(2)成员方法(非静态): 编译看左边,执行看右边
执行看右边因为存在方法重写;如果左边没有方法会报错
(3)构造方法: 还是进行分层初始化
(4)成员方法(静态) : 编译看左边,执行看左边
d. 多态的弊端:
不能访问子类的特有功能
e. 解决方案:
(1) 创建子类的具体对象,来访问自己的特有功能;虽然可以解决多态的弊端,但是从内存角度考虑,需要创建子类对象,那么必须在堆内存开辟空间,耗费内存,浪费空间!
(2) 向下转型:将父类的引用强制转换为子类的引用:前提必须有父类的引用存在;(向下转型必须依赖于向上转型!)
class Animal3{ public void show(){ System.out.println("show Animal2..."); } } //子类 class Cat3 extends Animal3{ public void show(){ System.out.println("show Cat2...."); } //特有功能 public void playGame(){ System.out.println("猫玩毛线..."); } } public class DuoTaiDemo4 { public static void main(String[] args) { //父类引用指向子类对象 Animal3 a = new Cat3() ; //向上转型 a.show() ; //不能访问子类特有功能 // a.playGame(); //创建子类具体对象 /* Cat3 c = new Cat3() ; c.playGame() ;*/ //父类的引用强制转换为子类的引用:向下转型 Cat3 c = (Cat3) a ; c.playGame() ; }
3.抽象类
a. 概念:
每一个动物的吃和睡的功能不一样,不应该把动物类定义为一个具体类,而是给出一个声明(abstract)
当一个类中如果有抽象功能(抽象方法)的时候,那么这个类一定要定义为抽象类!
public abstract class A {}
一个抽象类中可以抽象,也可以有非抽象的(作为一个判断题记忆!)
b. 特点:
抽象类不能实例化:抽象类不能创建对象
抽象类的子类不为抽象类
c. 实例化方式:
通过抽象类多态形式:父类的引用指向子类对象,通过子类进行初始化!
Fu fu = new Zi();
d. 抽象类多态 :
强制子类必须重写当前抽象的父类中所有的抽象方法
abstract class Animal{ //抽象方法:没有方法体的一个方法 public abstract void eat() ; public abstract void sleep() ; //具体方法 /public void eat(){ System.out.println("eat"); }/ public void show(){ System.out.println("show Animal...."); } } //抽象的子类 //abstract class Cat extends Animal{ // //} //子类是具体类 class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼"); } @Override public void sleep() { System.out.println("猫趴着睡觉.."); } } //测试类 public class AbstractDemo { public static void main(String[] args) { //当前Animal已经被abstract修饰了 // Animal a = new Animal();//Cannot instantiate the type Animal:抽象类不能实例化:instaceof //多态:父类引用指向子类对象 Animal a = new Cat() ; //Animal是抽象类,---->抽象类多态形式 a.eat() ; a.sleep() ; } }
e. 抽象类的成员特点 :
(1) 成员变量:可以是变量也可以是自定义常量
(2) 成员方法:可以有抽象方法,也可以有非抽象方法
抽象方法:强制子类必须要做到一件事情:方法重写(覆盖)
非抽象方法:由继承保证可以去提高代码的复用性
(3)构造方法 :抽象类可以有构造方法:包括有参构造和无参构造;通过抽象类多态的形式:让子类进行数据的初始化
f. 注意事项 :
(1) 没有抽象方法也可以定义为抽象类
(2) 不能和 private、final、static一起用
(3) alt + shift + s - > c 生成无参构造、o 生成有参构造、r 生成setXXX\getXXX方法
4.接口
a. 概念:
接口体现的是一种:扩展功能: 比如:猫可以跳高(并不是所有的猫都具有跳高功能)
interface 接口名{}
b. 特点:
(1) 接口中不能有非抽象方法
(2) 接口中不能有构造方法
(3) 不能实例化(不能直接创建对象)
c. 实例化方式 :
接口的子实现类:
(1)接口的子实现类是抽象类,没有意义,子类都不能创建对象了;实际开发中用的就是子类的对象进行初始化!
(2)接口的子实现类是非抽象类
接口的实例化:就是通过子实现类对数据进行初始化!
d.子实现类 :
class 子实现类名 implments 接口名{}
e. 成员特点 :
(1) 成员变量 :只能是常量:存下默认修饰符:public static final (永远建议自己给出默认修饰符)
(2) 成员方法 :接口中的成员方法默认修饰符:public abstract(永远建议自己给出默认修饰符)
(3) 构造方法 :没有构造方法
interface Inter{ public static final int num = 100 ; public static final int num2 = 200 ; //抽象方法 // public void show(); // void show() ; //全部给出默认修饰符 public abstract void show() ; //接口没有构造方法 // public Inter(){ // // } public abstract void function() ; } //定义接口的子实现类:见名知意:接口名+impl class InterImpl implements Inter{ @Override public void show() { System.out.println(num); System.out.println(num2); } @Override public void function() { System.out.println("function InterImpl..."); } } //测试类 public class InterfaceDemo2 { public static void main(String[] args) { //创建接口对象:接口多态的形式 Inter i = new InterImpl() ; // i.num = 20 ;//当前num变量:被final修饰 System.out.println(Inter.num);//接口名.成员变量(当前变量被static修饰) System.out.println(Inter.num2); System.out.println("-------------"); i.show() ; i.function() ; } }
5.关系
a. 类与类 :
继承关系:extends,java中只支持单继承,不支持多继承,但是可以多层继承!
b. 类与接口:
实现关系:implements,并且,一个类在继承另一个类的同时,可以实现多个接口
c. 接口与接口 :
继承关系:extends,可以支持单继承,也可以多继承!
d. 接口与抽象类的区别 :
成员的区别:
(1)成员变量:
1)抽象类:成员变量可以是常量,也可以是变量
2)接口:成员变量只能是一常量:存在默认修饰符:public static final
(2) 构造方法:
1)抽象类:可以有无参构造,有参构造方法
作用:通过子类进行数据初始化(通过子类创建对象)
接口:没有构造方法的
(3)成员方法的区别:
1)抽象类:可以有抽象方法,也可以有非抽象方法
2)接口:只能是抽象方法:存在默认修饰符:public abstract
(4)关系的区别:
1)类与类的关系:
继承关系:extends,java中只支持单继承,不支持多继承,但是可以多层继承!
2)类与接口的关系:
实现关系:implements,并且,一个类在继承另一个类的同时,可以实现多个接口
3)接口与接口的关系
继承关系:extends,可以支持单继承,也可以多继承!
(5)设计理念的区别:
1)抽象类:
体现的是一种"is a"的关系,存在继承关系!(抽象类多态)
2)接口:
体现的是一种"like a"的关系,由于接口的一种扩展功能
6.API文档的制作
a. API的使用:
(1)打开API:
1)显示---->输入你查找的类
2)索引---->搜索
(2)找到某一个类:
1)对该类的描述
2)看类结构:
3)看该类是否有字段(变量),构造方法(如何创建该类对象),方法(类的成员方法)
4)出现该类的版本号b. API的制作 :
(2)需要定义一个类工具类:ArrayTool数组工具类:给该类写上文档注释(每一个静态方法都需要使用文档注释)
(2)需要将该类的无参私有化,目的是为了让外界创建对象
(3)ArrayTool中的成员方法全部用static修饰
(4)打开dos---->javadoc -d 目标名(文件名) -author -version ArrayTool.java
package org.westos.版本2; /** * * 该类是针对数组操作的一个工具类,里面有一些对数组操作的功能 * @author Apple * @version V1.0 * */ public class ArrayTool { //无参构造私有,目的为了不让外界其对象 private ArrayTool(){ } /** * 该方法是针对数组的遍历的方法,遍历的元素[元素1, 元素2, 元素, ....] * @param arr :需要被遍历的数组 * */ public static void printArray(int[] arr){ System.out.print("["); for(int x = 0 ; x < arr.length ; x ++){ if(x==arr.length-1){ System.out.println(arr[x]+"]"); }else{ System.out.print(arr[x]+", "); } } } /** * 该方法是针对数组获取最大值的方法 * @param arr :需要被遍历的 数组,可以获取每一个元素 * @return 返回的就是数组中最大值 * * */ public static int getMax(int[] arr){ //定义参照物 int max = arr[0] ; //遍历其他索引 for(int x = 1 ; x < arr.length ;x ++){ //判断 if(arr[x]>max){ max = arr[x] ; } } return max ; } /** * 该方法是查询数组中的元素在数组中第一次出现的索引 * @param arr : 需要查询的数组 * @param value:需要被查找的远古时 * @return 如果查到了当前索引对应的元素,那么就直接返回当前索引,如果查不到,则返回-1 * */ public static int getIndex(int[] arr,int value){ //假设法 //定义一个索引:假设查不到 int index = -1 ; //遍历数组 for(int x = 0 ; x < arr.length ; x ++){ //判断:如果刚好查到的x索引对应的元素和value相等,那么返回该索引 if(arr[x]==value){ //表查到了 //给索引遍历重新赋值 index = x ; break ; } } return index ; } }
7.形式参数和返回值
a. 形式参数为引用类型 :
(1)具体类 :如果形式参数是一个具体类,那么需要创建该类对象(用new命令new一个对象传入)匿名对象的应用 : new Demo.method(new A());(2)抽象类 :如果形式参数是抽象类的情况,那么需要自定义一个抽象类的子类,来进行实例化(创建对象)!,创建对象的实质:抽象类多态!匿名对象的应用 : new Demo.method(new Zi());(3)接口 : 如果形式参数是接口情况,那么需要自定义一个接口的子实现类,然后通过接口多态的形式给接口进行实例化!(接口多态!)匿名对象的应用 :内部内部类;b. 返回值为引用类型 :
(1)具体类 :直接返回该类对象(通常实际开发中使用的是匿名对象)
return new A();
(2)抽象类 :返回值如果是抽象类,需要的返回是该抽象类的子类对象
return new Zi();
(3)接口 :返回值如果是接口类型,需要的是返回该接口的子实现类对象(通过子实现类进行实例化!)
应用匿名内部类 ;
8.内部类:
a. 定义 :
在一个类中定义另一个类,那么把这种情况:内部类:b. 分类 :
(1)成员内部类 :在外部类的成员位置
(2)局部内部类 :在外部类的局部位置定义的这个类
c. 成员内部类 :
(1)外部类名.内部类名 对象名 = 外部类对象.内部类对象;
例:Outer.Inner oi = new Outer().new Inner() ;
(2)内部类可以访问外部类的任意成员变量(无论是不是private)
(3)静态成员内部类 :如果成员内部类被static修饰,那么要访问外部类的成员变量,这个变量必须被static修饰。
1):外部类名.内部类 对象名 =外部类对象.内部类对象;
Outer.Inner oi = new Outer.Inner() ;
2):对于静态的成员内部类来说,无论静态成员内部类中的成员方法是静态还是非静态的,要访问外部类的成员变量,该变量必须被static修饰
class Outer4{ //外部类的两个成员变量 public static int num = 10 ; public static int num2 = 20 ; /** * 结论: * 对于静态的成员内部类来说,无论静态成员内部类中的成员方法是静态还是非静态的,要访问外部类的成员变量,该变量必须被static修饰 * */ //定义一个静态的成员内部类 public static class Inner4{ //非静态的内部类的成员方法 public void show(){ System.out.println(num); System.out.println(num2); } //静态的内部类的成员方法 public static void show2(){ System.out.println(num); System.out.println(num2); } } } //测试类 public class InnerDemo4 { public static void main(String[] args) { //需求:要访问静态成员内部类Inner4里面的show(),show2()方法 //外部类名.内部类 对象名 =外部类对象.内部类对象; // Outer4.Inner4 oi = new Outer4().new Inner4() ; // oi.show() ; //静态的成员内部类访问该类中的成员方法: //格式:外部类名.内部类名 对象名 = new 外部类名.内部类名() ; Outer4.Inner4 oi = new Outer4.Inner4() ; oi.show() ; oi.show2() ;//静态方法 System.out.println("--------------"); //show2()还有另外一种访问方式: Outer4.Inner4.show2() ; } }
d. 局部内部类 :
(1)定义 : 定义在外部类的局部位置
(2)无论是局部内部类还是成员内部类(非静态的)都可以直接访问外部类的成员,包括私有
(3)局部内部类访问局部变量会出现问题
当前局部变量报错,必须用final修饰
是由于局部变量是随着方法调用而生成的,随着方法的调用完毕消失,而现在局部位置有一个局部内部类它要在自己的成员方法位置访问当前的局部变量必须把变量变成一个常量,(需要用final:自定义常量),这样的一个变量的值永远是固定的!
(4)外部类调用局部内部类的方法 :创建外部类对象,用外部类调用成员方法,成员方法内部调用局部内部类
class Outer5{ //外部类的成员变量 // public int num = 100 ; private int num = 100 ; //外部类的成员方法 public void method(){ //局部变量 final int num2 = 200 ; //自定义常量(细节问题) //局部位置 class Inner5{ //局部内部类的成员方法 public void show(){ System.out.println(num); //局部内部类中访问局部变量 System.out.println(num2); //jdk1.7才会有这个错误! jdk1.8---->封装好了,所以不会出现错误! } } Inner5 i = new Inner5() ; i.show() ; } } //测试类 public class InnerDemo5 { public static void main(String[] args) { //对于局部内部类访问具该类的成员方法:创建外部类对象 使用外部类对象调用外部类的成员方法 Outer5 o = new Outer5() ; o.method(); } }
f. 匿名内部类:
(1)定义 :是内部类的简化版格式
new 接口名或者类名 {}
(2)前提条件 :必须存在一个接口或者是一个类(可以是具体类,也可以是一个抽象类)
(3)实质 :继承了该类(抽象类)或者是实现了该接口的子类对象!
(4)使用匿名内部类可以重写接口,并调用接口中的方法
另一种形式:Inter i = new Inter(){ @Override public void show() { System.out.println("show"); } @Override public void show2() { System.out.println("show2"); } }; //使用对象名调用 i.show(); i.show2() ;
第二种方法一般适用于接口中仅有一种方法new Inter(){ @Override public void show() { System.out.println("show"); } @Override public void show2() { System.out.println("show2"); } }.show() ;
(5)实际应用
package org.westos_内部类; /** * 匿名内部类在开发中的使用 * */ interface Inter3{ public abstract void study() ; } class StudentDemo{ public void method(Inter3 i){//形式参数是一个接口 i.study() ; } } //测试类 public class OuterTest { public static void main(String[] args) { //需求:调用StudentDemo中的method()方法 StudentDemo sd = new StudentDemo() ; Inter3 i = new Armay() ; i.study() ; System.out.println("---------------------"); //方式2:匿名内部类 StudentDemo sd2 = new StudentDemo() ; sd2.method(new Inter3(){ @Override public void study() { System.out.println("好好学习,天天向上..."); } }) ; } }
g. 内部类中调用外部类同名成员变量 :
(1) 使用匿名对象
new Outer().xxx = ...;
(2)使用外部类this限定 :
Outer.this.xxx = ...;