基本概念
- 成员变量、构造器、方法的构造顺序随意,不会造成不同的影响
- 带static的方法不能访问非static的方法、变量
- 如果没有构造器,将调用默认的无参构造,如果定义了显式构造器,默认构造器将失效
-
构造器就是一种特殊的方法,编译器通过有无定义返回值来区分构造器和方法
修饰符访问控制表
类和对象
-
一个类方法的方法体内可以直接调用本类的另一个类方法
- 不能直接调用对象方法
- 如果一定要调用,只能在类方法中new一个对象再调用
-
对象方法的方法体内可以调用本类另一个对象方法
- 可以加this,也可以省略
- 如果省略this,就默认this为调用者
-
可以使用对象来调用类方法、类变量
- 但是,不推荐这样做
- 推荐使用类名来调用类方法、类对象
-
构造器中的this就代表正在创建的对象
-
new对象后,各种部件的创建顺序:
- 父类静态变量
- 父类静态初始化块
- 子类静态变量
- 子类静态初始化块
- 父类成员变量
- 父类初始化块
- 父类构造器
- 子类成员变量
- 子类初始化块
- 子类构造器
方法
-
作为完全的面向对象语言,Java中的方法都不是独立的实体,必须通过类或对象来调用
-
方法中的参数传递机制:
- 只有一种方式,值传递
- 调用方法后,在方法栈区新开辟一个栈区,并复制变量的值(基本类型)或者变量的地址(引用类型)给栈区内的形参
- 操作基本变量时,只是操作了数值的副本,原先的基本变量值并没有变化
- 操作引用变量时,传入的是对象地址的副本,实际操作的是对象,因此对象会发生变化,这一点与基本变量不同
-
一个方法的标识包括以下三个
- 调用者
- 方法名
- 方法的形参
调用者.方法名(参数1,参数2,……)
- 返回值和修饰符不是标识
- 所谓重载,就是调用者和方法名相同,形参不同,与返回值和修饰符没有关系
-
形参个数可变的方法
- 最后一个形参的类型后加上三个点...
- 实际上会在方法体中被组装为数组
变量
- 分为成员变量、局部变量
- 如果局部变量和成员变量同名,成员变量会被覆盖,此时可以通过this调用成员变量
- 一般在构造器中使用较多
- 方法中应尽量避免
- 成员变量的内存运行机制:
执行Person person = new Person()
- 首先在堆内存中创造一个类对象,并初始化类变量、执行静态初始化块。
- new之后,在堆内存创建一个Person对象,并初始化非静态成员变量,指向字符串常量“张三”
-
在栈内存创建person变量,并指向堆内存中的Person对象
隐藏和封装
-
利用访问控制符,控制变量和方法的隐藏和暴露
- 外部类只能使用public和default,不能是protected和private
- public的外部类必须与文件名对应
-
类的设计应遵循:
- 高内聚:内部变量、实现方法应隐藏,禁止外界干预
- 低耦合:只暴露少量方法供外部调用
-
控制符使用原则
- 成员变量都应是private,使用setter和getter
- 工具方法都应private
- 如果仅在本包内使用,使用default
- 如果方法仅希望被子类改写,不希望被外界调用,则设为protected
构造器
- 如果不定义构造器,会调用默认的无参构造器,默认构造器没有参数,不进行任何操作
- 一旦提供自定义的构造器,默认的无参构造器就会失效
- 编写参数不同的多个构造器,称为构造器重载
- 在一个构造器中调用
this(参数1,参数2)……
,可实现调用另一个构造器。- 调用this的语句只能是构造器的第一句
继承
-
extends意为扩展,这个翻译比继承更清晰:子类是父类功能的扩展
- 子类获得父类的成员变量和方法
- 父类的构造器会在子类构造器执行前执行
- 子类可以重新定义父类中已有的实例变量,并覆盖
- 子类可以重写父类的方法
-
方法重写的原则:两同两小一大
- 方法名、形参列表相同
- 子类方法返回值类型≤父类方法
- 子类方法抛出异常类型≤父类方法
- 子类方法的访问权限≥父类方法
-
super相关
- 在子类中可以使用super调用父类的实例方法
- 在子类中可以使用父类类名调用父类的类方法
- 当新建子类实例时,也会为父类的实例变量和方法分配内存,方便使用super调用
-
子类的构造器总会先调用父类的构造器,分为以下几种情况:
- 子类构造器的第一句调用了super(参数...),则根据参数调用父类构造器
- 子类构造器没有使用super,则会隐式调用父类的无参构造器
- 子类构造器调用了this(),则会调用本类另一个构造器,而另一个构造器总会调用父类构造器
- 父类有有参构造器,子类无构造器,编译出错
多态
-
定义:当一个父类变量引用了一个子类对象时,使用父类变量调用的方法,实际运行的是子类的方法,这就是多态
- 本质是变量的编译时类型和运行时类型不同
- 变量的编译时类型是声明类型
- 变量的运行时类型是对象类型
-
发生条件:
- 子类和父类都存在该方法,执行子类中的方法
- 子类存在方法,父类不存在,编译错误,因为编译时找不到引用变量的方法
- 父类存在方法,子类不存在,依然执行子类的方法(从父类继承)
-
重要:实例变量不具有多态性,使用父类变量调用实例变量,实际调用的是父类对象的实例变量,而不是子类的
- 一般不会出现,因为大多数实例变量都是private
-
如果要调用父类中不存在的子类方法,就需要强制类型转换为子类引用
instanceof运算符
- 一般左边是变量,右边是类,用于判断一个变量指向的对象
Object s = "abc"
s instanceof Object,返回true
s instanceof String,返回true
s instanceof String的子类,返回false
s instanceof Integer,编译出错,String和Integer没有继承关系
- 一般用于强制类型转换之前,判断一个父类的引用是否指向某一个子类的实例
if(s instanceof String) String str = (String) s;
\\不会出现ClassCast异常,使代码更加健壮
通过组合实现复用
- 实现类的复用,除了使用继承之外,另一种方式是组合
- 组合就是把被复用类作为新类的成员变量,在new时传入复用类的实例,这样也能在新类中使用复用类的所有功能
- 使用场景
- 在is-a关系时使用继承,例如动物-狗-泰迪
- 在has-a关系时使用组合,例如电脑-内存/硬盘/cpu
初始化块
- 修饰符只能是空或static
- 初始化块和实例变量的初始化一起在构造器执行之前执行
- 实际上,编译后初始化块的内容会被加入到每个构造器方法体的前面
- 只有在第一次使用类时对静态块进行初始化,之后就不再调用static块里的内容
- 使用方法:
- 初始化块不接受任何参数
- 各个构造器中重复的语句,如果不调用参数,就适合放在初始化块中
- 各个构造器中重复的语句,如果要接受参数,适合用this调用其他构造器
网友评论