目录
面向对象
面向对象(指挥者)概述
Java语言是一种面向对象的程序设计语言,这里的对象泛指现实中一切事物,每种事物都具备自己的属性(成员变量)和行为(成员方法)。
面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。
它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。
面向对象语言的三大基本特征
封装、继承和多态。
类与对象
类
是一组相关属性和行为的集合。可以看成是一类事物的模板。
描述一类事物: 属性:就是该事物的状态信息; 行为:就是该事物能够做什么。对象
是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为。
类和对象的关系
类是对一类事物的描述,是抽象的。
对象是一类事物的实例,是具体的。 类是对象的模板,对象是类的实体。类的定义格式
public class ClassName{ //成员变量 //成员方法}
定义类:就是定义类的成员,包括成员变量和成员方法。
成员变量:和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外。 成员方法:和以前定义方法几乎是一样的。只不过把static去掉。对象的使用格式
创建对象:
类名 对象名 = new 类名();
使用对象访问类中的成员:
对象名.成员变量; 对象名.成员方法();
成员变量的默认值
成员变量和局部变量的区别
对象作为参数
当一个对象作为参数,传递到方法中时,实际上传递的是对象的地址值
对象作为返回值
public static Phone getPhone() { Phone one = new Phone(); one.brand = "苹果"; one.price = 8388.0; one.color = "玫瑰金"; return one; //地址值 }
当使用一个对象类型作为方法的返回值时,返回值就是地址值
封装
封装性在Java当中的体现:
- 方法就是一种封装
- 关键字private也是一种封装
封装就是将一些细节信息隐藏起来,对于外界不可见。
封装原则
将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。
封装步骤
- 使用 private 关键字来修饰成员变量。
- 对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法
举例
问题描述:定义Person的年龄时,无法阻止不合理的数值被设置进来。
解决方案:用private关键字将需要保护的成员变量进行修饰。一旦使用了private进行修饰,那么本类当中仍然可以随意访问。
但是!超出了本类范围之外就不能再直接访问了。间接访问private成员变量,就是定义一对儿Getter/Setter方法
必须叫setXxx或者是getXxx命名规则。
对于Getter来说,不能有参数,返回值类型和成员变量对应; 对于Setter来说,不能有返回值,参数类型和成员变量对应。右键Generate
或 alt + insert(fn+Enter)
可以自动生成
public void setAge(int num){ if( num < 100 && num >= 0) { age = num;} else { System.out.println("数据不合理");}}public int getAge(){ return age;}
注意:布尔类型的Getter不是用getXxx(),而是isXxx();Setter不变
This
当方法的局部变量和类的成员变量重名的时候,根据“就近原则”,优先使用局部变量。
如果需要访问本类当中的成员变量,需要使用格式:this.成员变量名
“通过谁调用的方法,谁就是this。” this -- 地址
Person Person.name
构造方法
public 构造方法名(参数列表){ // 方法体}
构造方法是专门用来创建对象的方法,用new
创建对象,其实是调用构造方法。
构造方法的写法上,方法名与它所在的类名相同。
它没有返回值,所以不需要返回值类型,甚至不需要void
构造方法不能return一个具体的返回值
如果没有没有编写任何构造方法,那么编译器会默认赠送一个构造方法,没有参数,方法体什么也不做。
一旦编写了至少一个构造方法,那编译器不再赠送
构造方法可重载(名称相同,参数列表不同)
构造方法和成员方法的区别
标准代码——JavaBean
一个标准的类通常要拥有下面四个组成部分:
- 所有的成员变量都要使用private关键字修饰
- 为每一个成员变量编写一对儿Getter/Setter方法
- 编写一个无参数的构造方法
- 编写一个全参数的构造方法
这样标准的类也叫做Java Bean
打印想要格式的数组
import java.util.Arrays;System.out.println(Arrays.toString(arr));
ctrl + 点toString
可以看系统里这个方法是怎么写的
导包
指出需要使用的类,在什么位置
import 包名称.类名称;
对于和当前类属于同一个包的情况,可以忽略导包语句不写。
如果调用不同包的成员变量
在那个包的成员变量前 + public
public String name
继承 extends
继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接 访问父类中的非私有的属性和行为。
在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当做父类看待。
例如父类是员工,子类是讲师,那么“讲师就是一个员工”。关系:is-a。定义父类的格式:(一个普通的类定义)
public class 父类名称 { // ...}
定义子类的格式:
public class 子类名称 extends 父类名称 { // ...}
成员变量重名
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰父类成员变量,类似于之前学过的 this 。
使用格式:
super.父类成员变量名
通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员变量呢?对!可以在父类中提供公共的getXxx方法和setXxx方法。
注意事项:
无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问子类成员变量有两种方式:
直接通过子类对象访问成员变量:
等号左边是谁,就优先用谁,没有则向上找。 间接通过成员方法访问成员变量: 该方法属于谁,就优先用谁,没有则向上找。成员方法重名——重写(Override)
方法重写(Override): 子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。
重载(Overload):方法的名称一样,参数列表【不一样】。特点:创建的是子类对象,则优先用子类方法。如果没有都是向上找父类,绝对不会向下找子类的。
应用:子类可以根据需要,定义特定于自己的行为。既沿袭父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。
super.父类成员方法,表示调用父类的成员方法。注意:
- 子类方法覆盖父类方法,必须要保证子类权限大于等于父类权限。
- 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。
方法重写的注意事项
必须保证父子类之间方法的名称相同,参数列表也相同。
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写。 这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。子类方法的返回值必须【小于等于】父类方法的返回值范围。 ???
小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。子类方法的权限必须【大于等于】父类方法的权限修饰符。
小扩展提示:public > protected > (default) > private 备注:(default)不是关键字default,而是什么都不写,留空。
大部分情况下,方法重写 重写的方法 修饰符、返回值类型都是一样的
设计原则
对于意见投入使用的类,尽量不要进行修改。
推荐定义一个新的类,来重复利用其中的共用功能,并且添加新功能。父子类构造方法的访问特点
- 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。父类空间优先于子类对象产生
- 子类构造可以通过super关键字来调用父类重载构造。
- super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
总结:
子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。
super 和 this
super :代表父类的存储空间标识(可以理解为父亲的引用)。
this :代表当前对象的引用(谁调用就代表谁)。
super() 和 this() 两种构造调用都必须是在构造方法的第一行,所以不能同时出现
1、访问成员
this.成员变量 ‐‐ 本类的 super.成员变量 ‐‐ 父类的 this.成员方法名() ‐‐ 本类的 super.成员方法名() ‐‐ 父类的2、访问构造方法
this(...) ‐‐ 本类的构造方法 如:本类的无参构造,调用本类的有参构造 super(...) ‐‐ 父类的构造方法 例:super(20); // 在调用父类重载的构造方法继承的特点
Java只支持单继承,不支持多继承
Java支持多层继承(继承体系)。
顶层父类是Object类。所有的类默认继承Object,作为父类。
子类和父类是一种相对的概念。
抽象类
抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。
定义格式:
abstract class 类名字{}
代码举例:
public abstract class Animal { public abstract void run(); }
抽象方法
抽象方法:在不确定对象的前提下,要求确定行为。就是加上abstract关键字,然后去掉大括号,直接分号结束。
定义格式:
修饰符 abstract 返回值类型 方法名 (参数列表);
代码举例:
public abstract void run();
如何使用抽象类和抽象方法
- 不能直接创建new抽象类对象。
- 必须用一个子类来继承抽象父类。 否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法
- 子类必须覆盖重写抽象父类当中所有的抽象方法。 覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
- 创建子类对象进行使用。
一个抽象类不一定含有抽象方法,只要保证抽象方法所在的类是抽象类即可。
这样没有抽象方法的抽象类,也不能直接创建对象,在一些特殊场景下有用途。
注意事项
- 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
- 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
- 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
- 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
接口
一种引用类型,方法的集合,接口的内部主要就是封装了方法,包含:
抽象方法(JDK7及以前)
默认方法和静态方法(JDK8)
私有方法(JDK9)
接口的定义
与定义类相似,但是使用interface关键字。它也会被编译成.class,但它不是类。
定义格式(接口名称大驼峰)
public interface 接口名称 { //抽象方法 //默认方法 //静态方法 //私有方法}
含有抽象方法
抽象方法:
- 使用abstract关键字修饰,可以省略。没有方法体。该方法供子类实现使用。
- 接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。
public interface InterFaceName{ public abstract void method();}
含有默认方法和静态方法
默认方法:
使用default修饰,不可省略。
- 接口的默认方法,可以通过接口实现类对象,直接调用。
- 接口的默认方法,也可以被接口实现类进行覆盖重写。
- 接口中,有多个默认方法时,实现类都可以继承使用。如果默认方法有重名的,必须重写一次。
静态方法:
使用static修饰,供接口直接调用。
注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。 正确用法:通过接口名称,直接调用其中的静态方法。调用格式:接口名称.静态方法名(参数);
public interface InterFaceName{ public default void method(){ //执行语句 } public static void method2(){ //执行语句 }}
接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
含有私有方法和私有静态方法
私有方法:使用private修饰,供接口中的默认方法调用。
私有静态方法:默认方法和静态方法可以调用。public interface InterFaceName{ private void method(){ //执行语句 } private static method(){ //执行语句 }}
接口的使用
接口不能创建对象,但是可以被实现(implements,像继承)。一个实现接口的类(可以看作是接口的子类),需要实现接口中所有的抽象方法(alt+enter),创建该类对象,就可以调用方法了,否则它必须是一个抽象类。
class 类名 implements 接口名{ //重写接口中抽象方法【必须】 alt+enter //重写接口中默认方法【可选】}
接口的多实现
一个类可以实现多个接口,这叫做接口的多实现。一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB { // 覆盖重写所有抽象方法}
优先级的问题。父类是亲爸爸,接口是干爸爸。
一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。
接口继承
一个接口能继承另一个或者多个接口。接口的继承使用extends关键字。如果父接口中的默认方法有重名的,那么子接口需要重写一次。
- 子接口重写默认方法时,default关键字可以保留。
子类重写默认方法时,default关键字不可以保留。
接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰。
从效果上看,这其实就是接口的【常量】。
public static final 数据类型 常量名称 = 数据值;
备注:
一旦使用final关键字进行修饰,不可改变,必须赋值。注意事项:
- 接口当中的常量,可以省略public static final,注意:不写也照样是这样。
- 接口当中的常量,必须进行赋值;不能不赋值。
- 接口中常量的名称,使用完全大写的字母,用下划线进行分隔,如NUM_OF_MY_CLASS。(推荐命名规则)
ctrl+shift+U
:大小写替换
调用:
接口名称.常量名称
其他特点
接口是没有静态代码块或者构造方法的。
多态
多态是指同一行为,具有多个不同表现形式。
前提【重点】
1、继承或者实现【2选1】
2、方法的重写【不重写,无意义】 3、父类引用指向子类对象【格式体现】 格式:父类名称 对象名 = new 子类名称();
或者:
接口名称 对象名 = new 实现类名称();
变量名.方法名();
访问成员变量的两种方式
- 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找。
- 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找。
编译看左边,运行看右边
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后的方法。
在多态的代码当中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找。口诀:编译看左边,运行看右边。
对比一下:
- 成员变量:编译看左边,运行还看左边。
- 成员方法:编译看左边,运行看右边。
引用类型转换
向上转型【多态写法】
多态本身就是子类类型向父类类型向上转换的过程,这个过程是默认的。
当父类引用指向一个子类对象时,便是向上转型。 使用格式:父类类型 变量名 = new 子类类型();
向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:
对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。解决方案:用对象的向下转型【还原】。
向下转型
父类类型向子类类型向下转换的过程,这个过程是强制的。
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式。 使用格式:子类类型 变量名 = (子类类型)父类变量名
instanceof关键字
为避免ClassCastException的发生,Java提供了instanceof关键字,给引用变量做类型的校验。
格式:变量名 instanceof 数据类型
如果变量属于该数据类型,返回true。
如果不属于,返回false。