面向对象(一)

面向对象

《疯狂Java讲义》学习笔记

构造器

  • 修饰符:public protected private 的其中一个修饰符

  • 构造器名:必须和类名相同
    :构造器既不能定义返回值类型,也不能使用 void 声明构造器没有返回值。如果给构造器定义返回值类型,或者使用 void 声明构造器没有返回值,编译不会报错。但是 Java 会把这个所谓的构造器当成方法来处理。

  • 构造器返回值:返回该类的实例

  • 如果没有定义构造器,系统会提供一个默认的构造器

  • static 修饰的变量或者方法即可以使用类名.变量名 | 方法名 调用,也可以使用 对象.变量名 | 方法名

Person p = new Person();
  • 对象放在堆内存中,变量p放在栈内存中
  • 对象的 this 引用:this 关键字总是指向调用该方法的对象
  • this 作为对象的默认引用有两种情形
    ① 构造器中引用该构造器正在初始化的对象
    ② 在方法中调用该方法的对象
  • 静态成员不能访问非静态成员
  • 可以把 this 当做返回值:如果在某种方法中把 this 作为返回值,则可以连续多次调用该方法
public class TestThis {
    int count;

    public TestThis calculate() {
        count++;
        return this;
    }

    public static void main(String[] args) {
        TestThis testThis = new TestThis();
        //连续3次调用calculate()方法
        testThis.calculate().calculate().calculate();
        //输出count的值
        System.out.println("count = " + testThis.count);//3
    }
}

方法

  • 方法的参数传递机制
    • 值传递:将实际参数的副本(复制品)传入方法内,参数本身不会受到影响
  • 形参个数可变的方法(JDK1.5之后):在最后一个参数的类型后面加三个点(…),多个参数值当成数组
  • 方法的重载:方法名相同,参数列表不同
  • 方法重载的要求:两同一不同,同一个类,方法名相同,参数列表不同
  • 至于其他部分,方法的返回值类型,修饰符等,与方法的重载没有任何关系

成员变量和局部变量

  • 成员变量分为类变量( static 修饰)和实例变量
  • 如果通过 对象 . 类变量修改类变量的值,那么导致该类的所有实例访问改类变量都会得到修改之后的值
  • 成员变量无需显示初始化,系统会进行默认初始化
  • 局部变量分为:形参方法内局部变量代码块局部变量
  • 局部变量除了形参之外都需要显示进行初始化
  • Java允许局部变量和成员变量同名,局部变量会覆盖成员变量

封装

访问控制级别表
privatedefaultprotectedpublic
同一个类中
同一个包中
子类中
全局范围内

:对于外部类而言,只有 publicdefault 两种访问控制级别

package importimport static

  • package 位于Java源程序第一行非注释行,一旦源文件使用了 package ,那么这个文件的所有类都属于这个包
  • import package.subpackage …*; (*) 星号只能代表类,不能代表包。 package.subpackage 的子包中的类不会被导入
  • import static 静态导入:JDK1.5以后增加了静态导入语法,用于导入指定类的某个静态成员变量、方法、或全部的静态成员变量、方法
    • 静态导入的两种语法:
//导入指定类的单个静态成员变量、方法
//导入ClassName类中字段名为fieldName变量,或者方法名为methodName的方法
import static 包名.子包名.类名.字段名 | 方法名;
//导入指定类的全部静态成员变量、方法:星号只能代表静态变量和方法名
import static 包名.子包名.类名.*;

构造器重载

使用 this 调用另一个构造器:使用 this 调用另一个构造器时只能在构造器中使用,而且必须位于构造器执行体的第一行代码

封装

对于外部类而言,只有 publicdefault 两种访问控制级别

类的继承

  • Java的子类不能获得父类的构造器

  • 重写父类的方法:子类包含父类同名方法的现象被称为方法的重写

  • 方法重写要遵循:两同两小一大的原则
    两同 :方法名相同,形参列表相同
    两小

    • 子类的返回值类型比父类的返回值类型更小或者相等
    • 子类方法抛出的异常应该比父类抛出的异常更小或者相等

    一大 :子类的访问权限应该比父类的访问权限更大或者相等

  • 覆盖方法和被覆盖的方法要么都是类方法,要么都是实例方法

  • 子类覆盖父类的方法之后,子类就无法访问父类被覆盖的方法,但是可以在子类中使用 super (被覆盖的方法是实例方法)或者 父类类名 调用(被覆盖的方法是类方法)来调用父类被覆盖的方法

:如果父类的某个方法为 private 修饰,则该方法对于子类是隐藏的,子类就不能覆盖该方法,如果子类定义了一个与父类具有相同方法名,相同的形参列表,相同的返回值类型的方法,那么依然不是重写,而是在子类中重新定义了一个新的方法

super限定

  • 如果需要在子类中调用父类被覆盖的实例方法,可以使用 super 限定来调 super 也不能出现在 static 修饰的方法中
  • 当程序创建一个子类对象时,系统不仅会为该类定义的实例变量分配内存空间,也会为它从父类继承的所有实例变量分配内存空间,即使子类定义了与父类同名的实例变量
调用父类构造器
  • 子类使用 super 构造器调用父类构造器必须出现在子类构造器的第一行
    所以 this 调用和 super 调用不会同时出现

  • 不管是否使用 super 调用父类构造器,子类总会调用一次父类构造器
    ① 子类构造器使用 super 显示调用父类构造器,体统会根据 super 传入的参数调用父类对应的构造器
    ② 子类构造器使用 this 调用本类构造器,另一个构造器会调用父类对应的构造器
    ③ 子类既没有使用 super 显示调用父类构造器,也没有使用 this 调用本类构造器,则隐式调用父类无参构造器

  • 不管哪种情况,调用子类构造器初始化子类对象时,父类构造器总会在子类构造器之前执行。

  • 执行父类构造器时,系统会再次上溯执行其父类构造器,创建任何对象时,总是最先执行 java.lang.Object 类的构造器

多态

  • Java引用变量有两个类型:
    ① 编译时类型:由声明该变量时使用的类型决定
    ② 运行时类型:由实际赋给该变量的对象决定
  • 多态:编译时类型和运行时类型不一样
  • 向上转型:把一个子类对象直接赋值给父类对象时,无需任何转换或被称为向上转型,向上转型由系统自动完成
  • 当编译时类型是父类类型时,运行时类型为子类类型时,当运行时调用该引用变量的方法时:方法行为总是表现为子类的行为特征,
  • 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
  • 相同类型的变量、调用同一个方法时呈现出多种不同的行为特征,这就是多态
  • 与方法不同的是:对象的实例变量不具备多态性,程序访问的依然是父类的实例变量
  • 引用类型变量在编译阶段只能调用其编译类型所具有的方法,在运行时则执行它运行时所具有的方法。通过引用变量访问其包含的实例变量时,系统总是试图访问它编译时类型所定义的成员变量,而不是它运行时类型所定义的变量
引用变量的强制转换
  • 基本类型的转换只能在数值类型之间转换:包括整型、浮点型、 char (字符型);数值和 Boolean 类型之间不能转换
  • 引用类型之间转换只能在具有继承关系的两个类型之间进行转换;如果没有继承关系,强制转换则发生编译报错
  • instanceof :判断两个类型是否可以进行类型转换
  • instanceof 运算符的前一个操作符一般是引用类型的变量,后一个操作符是一个类,也可以是一个借口,用于判断前面的对象是否是后面的类,或是其子类、实现类的实例
  • 使用 instanceof 运算符时需要注意: instanceof 前面操作数的编译时类型要么与要么与后面类型相同,要么与后面的类具有父子类的继承关系,否则会编译出错

继承和组合

继承会破坏封装
  • 为了保证父类具有良好的封装性,不被子类随意改变,父类的设计尽量遵循如下规则:
    ① 尽量隐藏父类的内部数据,不要让子类直接访问父类的成员变量。
    ② 不要让子类可以随意访问、修改父类的方法。如果父类中的某些仅为辅助其他的工具方法,应该使用 private 修饰。
  • 如果父类的某些方法需要被外部调用,但又不希望子类重写该方法,可以使用 final 修饰。
    ① 如果希望被子类重写,不希望被其他类自由访问,可以使用protected修饰
    ② 尽量不要在父类构造器中调用将要被子类重写的方法
利用组合实现复用
  • 复用一个类的两种方法:
    继承 :子类继承父类,子类可以直接获得父类的 public 方法,程序使用子类时,可以直接访问子类从父类那里继承到的方法。
    组合 :把旧类对象作为新类的成员变量组合进来,用以实现新类的功能。
public class Test {

    public static void main(String[] args) {
        Animal a = new Animal();
        Bird b = new Bird(a);
        b.breath();
        b.fly();
    }

}

// 要复用的类
class Animal {
    private void beat() {
        System.out.println("心脏跳动...");
    }

    public void breath() {
        beat();
        System.out.println("吸一口气,吐一口气,呼吸中...");
    }
}

class Bird {
    // 把要复用的类组合到当前类中
    private Animal a;

    public Bird(Animal a) {
        this.a = a;
    }

    // 由于当前类不能直接调用Animal的breath()方法
    // 所以要重新定义一个自己的breath()方法
    public void breath() {
        // 通过Animal的对象调用Animal的breath()方法
        a.breath();
    }

    public void fly() {
        System.out.println("飞...");
    }
}

class Wolf {
    private Animal a;

    public Wolf(Animal a) {
        this.a = a;
    }

    public void breath() {
        a.breath();
    }

    public void run() {
        System.out.println("我在地上跑...");
    }
}

到底该用继承,还是组合:如果两个类有明确的整体、部分,如 Person 类需要 Arm 对象的方法( Person 对象由 Arm 对象组合),此时需要使用组合来完成复用

继承是用来表达( is-a )的关系,组合是( has-a )的关系

初始化块:(初始化块是Java类中可以出先的第四种成员)

[修饰符] {
	//修饰符只能是 static 或者没有,使用 static 修饰的初始化块成为静态初始化块。
	//初始化块里的点吗可以包含任何可执行的语句:
	包括定义局部变量、调用其他对象的方法、使用分支、循环语句
}
  • 初始化块总是先于构造器执行之前执行,先定义的初始化块先执行,后定义的初始化块后执行
  • 初始化块没有标识符,无法通过类、对象调用初始化块
  • Java创建对象的过程(前提是该类已经被加载进JVM中):
    ① 先为该对象的所有实例变量分配内存,
    ② 然后对这些变量进行初始化:
    a . 先执行初始化代码块或声明实例变量时指定的初始值(顺序与他们在源代码中的位置相同)
    b . 在执行构造器中指定的初始值
  • 静态初始化块:使用 static 修饰,也被称为类初始化块,通常用于对整个类进行初始化操作,先于普通初始化代码块执行
  • 系统执行静态代码块时会上溯到 java.lang.Object 类,先执行 java.lang.Object 的静态初始化块,在执行其父类的静态初始化块….最后在执行该类的静态初始化块
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值