Java面向对象
文章目录
- Java面向对象
- 1. 方法
- 2. 构造方法
- 3. 方法重载
- 4. 继承
- 5. 多态
- 6. 抽象类
- 7. 接口
- 8. 静态字段、方法
- 9. 包
- 10. 内部类
1. 方法
用
private
修饰field;外部通过
public
的getXxx()和setXxx()方法;this变量:方法内部的this始终
指向当前该类的实例
;可变参数:
类型... 名称
,如func(String… names),相当于数组类型使用可变参数的好处:
1. 如果使用数组,需要先构建数组,而使用可变参数不需要
2. 使用数组可以传入null,但可变参数在传入0个参数时,接受的是空数组而不是null传递参数时:
- 基本类型参数,是值的复制,互不影响
- 引用类型参数:调用方和接收方指向的是堆内存的同一个对象或数组
2. 构造方法
- 通过构造方法
初始化实例
; - 构造方法没有返回值(
void也没有
),方法名和类名相同
,通过new
来调用; - 默认有
空参构造器
,定义有参的,空参的就没了; - 引用类型未初始化是
null
,int是0
,布尔是false
; - 为方便代码复用,可在构造器内
调用其他构造器
; this(age,“lzh”);
3. 方法重载
- 类中一系列方法的
功能类似,只是参数不同
,可将其进行方法重载 - 方法名相同,返回值通常相同,如int indexOf(int ch); int indexOf(String str);
4. 继承
- extends将Student继承Person,会获得Peson的所有功能:字段和方法。父类中严禁定义同名字段;
- 一个类没有extends时,会
默认继承Object
; - 子类继承了所有(不包括构造方法),
但是无法访问私有字段、私有方法
; - 父类字段改为
protected
字段可以被子类访问;protected字段和方法被子类所访问; super
:表示父类;子类引用父类字段时:super.fieldName,因为子类继承后拥有该字段,也可写成this.fieldName;任何类的构造器的第一句必须是父类的构造器
,默认省略了super();所以父类要有无参构造器或显示调用其他super;阻止继承
:final class,表示该类不能继承向上转型
:People变量可以指向Student实例,People p = new Student();
因为Student继承Person,拥有Person全部功能。
这样 子类类型 => 父类类型
向下转型
:父类类型强制转换为子类类型,Student s = (Student)p;
若p指向的就是People类型,则向下转型失败
,因为p原本就是父类类型,子类多的功能无法实现;
instanceof
操作符:判断一个实例是不是某个类型(或者该类型的父类型)
Person p = new Student();if(p instanceof Stundet){Student s = (Student)p;}
- 子类和父类是
is
关系,使用继承;子类和某个类是has
关系,应把它作为子类的一个字段
5. 多态
方法重写
:子类定义了一个和父类方法签名完全相同的方法
;- Person p = new Student();如果子类重写父类run方法,那么p调用的是子类的run方法
实例方法是基于`运行时的实际类型的多态调用,而不是变量的声明类型
多态
:某个类型的方法调用,其真正执行的方法取决于运行时期的实际类型的方法
public void runTwice(Person p) {p.run();p.run();//无法知道传入的参数实际类型究竟是Person,还是Student.//当传入可变参数时,我们不需要知道它们属于什么类型,只需要知道调用run方法会调用它实际类型的run}
多态允许添加更多类型的子类实现;
重写Object方法:
- toString()
- equals()
- hashCode()
在子类中调用父类被重写的方法
:super.run();使用
final
设置一个父类方法不能被子类重写;final修饰的字段不能被修改
6. 抽象类
- 如果父类的被重写方法run(),没有实际意义,不需要实现任何功能,
只是为了定义方法签名以供子类去重写
,可将其声明为抽象方法
:abstract void run(); 没有方法体 - 抽象方法无法执行,那么所在的类就
无法实例化
,所以类也要声明为抽象类
:abstract class People{ }; - 设计抽象类就是
用于继承
,抽象类强迫子类实现抽象方法。抽象方法相当于定义了规范
; 面向抽象编程
:使用抽象类去引用具体的子类,尽量引用高层类型,避免引用实际子类型
;
Person s = new Student();Person t = new Teacher();// 不关心Person变量的具体子类型:s.run();t.run();
7. 接口
- 抽象类中可以有
字段、非抽象方法
,但接口
中没有字段,全都是抽象方法;
interface Person{void run();String getName();}
- 接口是比抽象类还抽象的纯抽象接口,方法都是public abstract,所以这俩可以不写
- 类是
实现接口
:implements,接口可以多实现; - 特殊的是:接口可以定义
常量、default方法
- 接口interface之间也可以继承,
相当于扩展了接口的方法
- 一般来说,公共逻辑适合放在abstract class中,具体逻辑放到各个子类,而接口层次代表抽象程度。
在使用的时候,实例化的对象永远只能是某个具体的子类
,但总是通过接口去引用它
,因为接口比抽象类更抽象:
List list = new ArrayList(); // 用List接口引用具体子类的实例Collection coll = list; // 向上转型为Collection接口Iterable it = coll; // 向上转型为Iterable接口
- 接口的default方法:default void run(){ }; 实现类不必重写default方法;
目的:给接口新增一个方法时,要修改全部实现子类
,所以新增一个default方法,这样子类可以不重写该方法,如果需要,也可以重写;
8. 静态字段、方法
- 前面class里定义的都是实例字段:
每个实例都有独立的字段,每个实例之间互不影响
; - 静态字段:static修饰;
一个所有该类的实例共享的字段
- 使用 类名.static字段 来访问静态字段;
- 静态方法:static void run(){}; 使用类名调用
因为静态方法属于类自身,所以静态方法内部无法使用this、无法访问实例字段,只能访问静态字段
;
常用于工具类Arrays.sort()、Math.random(),辅助方法:main()方法;
9. 包
解决类名冲突
,如不同人都写了个Person类- 一个类总属于某个包,比如Person只是简写的类名,全名应是 包名.Person
- 在定义class的
首行声明该类所在的包
- JVM运行时,看的是全类名,包不同,类就不同;
包没有父子关系,java.util和java.util.zip是不同的包
包作用域
:同一个包的类,可以访问包作用域的字段方法;缺省就表示包作用域(默认)import
:类中引用其他class,使用import导入该类,之后就可以写简单类名了;否则使用时要写全类名;- 编译器编译时,遇到一个class,如果是完整类名就直接查找;如果是简单类名就按顺序:
- 先查找当前package是否有该类;
- 再查找import导入的包中是否有;
- 最后在java.lang包中查找
因此,编译器编译时自动导入当前package的其他class、java.lang.*
(不包括lang包内部的包,java.lang.reflect这些)
10. 内部类
- 被定义在另一个类的内部;不能单独存在,
必须依附一个外部类的实例
- 先创建Outer实例,再通过
Outer.new
来调用内部类的构造器:Outer.Inner inner = outer.new Inner(); - Inner Class有
this
指向自己,还有一个Outer.this
指向外部实例; - Inner Class
可以修改外部类的private字段方法
; 匿名类
:不需要在外部类中明确定义;在方法内部使用匿名类来定义
(局部内部类)
通常是实例化接口,但接口不能实例化,需要实例化该接口的一个实现类,而该实现类名字不重要;
Runnable r = new Runnable(){//实现必要的抽象方法。。。}