导图社区 面向对象程序设计
为对象定义类:对象:代表现实世界中可以明确标识的一个实体,对象的状态(state,也成为特征和属性)是由数据域及其当前值来表示的。
编辑于2022-02-15 19:07:45面向对象
1. 为对象定义类
现实生活中是由很多很多对象组成的,基于对象抽出了类
对象:代表现实世界中可以明确标识的一个实体
对象的状态(state,也成为特征和属性)是由数据域及其当前值来表示的。
对象的行为(behavior,也称为动作)是有方法定义的。调用对象的一个方法就是要求对象完成一个动作
类:类别/类型,代表一类个体
类是对象的模子,对象是类的具体的实例
类中可以包含:
对象的特征(成员变量)
int a=0;
对象的行为(方法)
void (){ }
一个类可以创建多个对象
属性/特点
对象的属性/特定----实例变量
类的属性/特定------静态变量
超类中的方法不包含业务,需要被派生类重写,设计为抽象方法
2. 方法
方法签名
public void setMapReference(int xCoordinate,int yCoordinate){//方法代码} 上例中的方法签名是setMapReference(int,int)。 换句话说,它是两个整数的方法名称和参数列表。 public void setMapReference(Point position){// method code} Java编译器会让我们添加另一个方法,如上面的示例,因为它的方法签名不同,在这种情况下,setMapReference(Point) 。 public double calculateAnswer(double wingSpan,int numberOfEngines,double length,double grossTons){//方法代码} 在我们的Java方法签名的最后一个示例中,如果遵循与前两个示例相同的规则,则可以看到此处的方法签名是calculateAnswer(double,int,double,double) 。
方法签名的组成:
1、方法名
2、参数列表(形参类别、个数、顺序)
注意:
1、与返回值、修饰符以及异常无关
2、在Class文件格式之中,返回值不同,可以合法地共存于一个Class文件中
3、在泛型的使用中,参数List<String>与List<Integer>在经过类型擦除后,是相同参数
4、参数String... strings与参数String[] arr,是相同参数
方法重载
在一个类中有两个方法,它们都具有相同的名字但具有不同的参数列表。Java编译器根据方法签名决定使用哪个方法。731413
重载方法可以使得程序更清晰并具有可读性。具有不同参数类型但执行同样功能的方法用该使用相同的名字
重载的方法必须具有不同的参数列表。不能基于不同修饰符或返回值类型来重载方法。
有事调用一个方法是会有两个或更多可能的匹配,但编译器无法判断哪个是最精确的匹配。这称为歧义调用。歧义调用会产生编译错误。
3. 访问对象的数据和方法
在面向对象编程中,对象成员指该对象的数据城和方法。在创建一个对象之后,它的数据访问和方法调用可以使用点操作符(.)来进行,该操作符也称为对象成员访问操作符(object member access operator):
• objectRefVar.dataField 引用对象的数据域。
• objectRefVar.method(arguments)调用对象的方法
匿名对象
没有名字的对象,是对象的简化表示形式
使用场景:当被调用的对象只调用一次时(多次回创建多个对象浪费内存)
new 类名().方法名()//创建了一个对象并调用了方法
4. 构造方法
构造函数、构造器、构建器------服用给成员变量赋初值代码
构造方法必须和所在类同名
构造方法没有返回值类型,甚至连void也没有
构造方法是创建一个对象时由new操作符调用的。构造方法的作用是用于初始化对象
若自己不写构造方法,则编译器默认提供一个无参构造方法,
若自己写了构造方法,则不再默认提供
可以重载
5. this
指代当前对象,哪个对象调用方法它指的就是哪个对象
只能用在方法中,方法中访问成员变量之前默认有个this.
成员变量和局部变量是可以同名的
访问的时候默认采取的是就近原则
若想访问成员变量则this不能省略
当成员变量与局部变量同名时,若想访问成员变量this不能省略
当不同名时,一般情况下this都省略
this.方法名() 调用的是方法
一般不用
this() 调用的是构造方法
6. 堆栈
堆栈存什么:堆中存储new出来的对象(包括成员变量)、 栈中存储局部变量(包括方法的参数) 引用类型变量中存的是地址,基本类型变量中存的是值。 方法区:.class字节码文件(包括静态变量、所有方法)
null
表示空,没有指向任何对象,若引用的值为null,则该引用不能进行任何点操作了,若操作则发生NullPointerException空指针异常
7. 引用类型数组
对象的数组实际上是引用变量的数组
当使用new操作符创建对象数组后,这个数组中的每个元素都是默认值为null的引用变量
8. 继承
作用:代码复用
通过extends来实现继承
超类/父类:共有的属性和行为
派生类/子类:特有的属性和行为
派生类可以访问:派生类的+超类的 ,超类不能访问派生类的
一个超类可以有多个派生类,一个派生类只能继承一个超类------单一继承
具有传递性
儿子能继承爸爸传下来爷爷的东西
java规定:构造派生类之前必须先构造超类
在派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类无参构造方法
常见错误:父类里没有无参的构造方法,子类默认调时调不到,就会报错
在派生类的构造方法中若自己调用了超类的构造方法,则不再默认提供
super()调用超类构造方法,必须位于派生类构造方法的第一行(先父后子)
一个类想用另一个类,要么调用另一个类的对象,要么继承,继承过来就不需要调用了,但一个派生类只能继承一个超类
注意
和常规解释相反,子类并不是父类的一个子集。实际上,子类通常比父类包含更名的信息和方法。
父类中的私有数据域在该类之外不可访问。因此,不能在子类中直接使用。但是,如果父类中定义了公共的访问器/修改器,那么可以通过这些公共的访问器/修改器来访问/修改它们。
不是所有的“是一种”( is-a )关系都该用继承来建模。例如,正方形是一种矩形,但是不应该定义一个继承自Rectangle 类的Square类,因为 width 和 height 属性并不适用于正方形。相反,应该定义一个继承自GeometricObject 类的Square类,并为正方形的边定义一个side属性。
继承是用来建模 “是一种” 关系的。不要仅仅为了重用方法而盲目地继承一个类。例如,尽管 Person 类和Tree 类可以共享类似 height 和 weight 这样的通用特性,但是从Person 类继承出 Tree 类是毫无意义的。子类及其父类之间必须存在“是一种”关系。
某些程序设计语言允许从几个类派生出一个子类。这种能力称为多重继承(multiple inheritance)。但是在Java 中不允许多重继承。一个Java 类只可能直接继承自一个父类。这种限制称为单一继承(single inheritance)。如果使用 extends 关键字来定义一个子类,它只允许有一个父类。然而,多重继承可以通过接口来实现,这部分内容将在13.5 节中介绍。
9. super
指代当前对象的超类对象
类比this.,this调用自己的类(子类),super. 调用超类的属性/方法/构造方法, 一般省略,如果子类中的和超类中的重名则需要写明是指代自己类还是超类
super的用法:
super.成员变量名访问超类的成员变量(了解)
super.方法名()调用超类的方法
super()调用超类的构造方法
10. 向上造型
超类型的引用指向派生类的对象
超类型 引用 指向 派生类型 Animal o = new Tiger(); //向上造型
o.只能点出来Animal里的来,Tiger里特有的点不出来
能点出来什么,看引用的类型-----------这是规定,记住就OK了
11. 方法的重写
方法重写的概念
子类需要修改父列中定义的方法的实现,这称为方法重写
在子类中,出现了和父类方法声明完全一样的方法就是方法重写
方法名,参数列表,返回值类型都一样,只是方法体不一样。
方法重写的格式
和父类方法声明一样
要重写一个方法,需要在子类中使用和父类一样的签名来定义该方法
方法重写的场景
当父类方法的功能不能满足子类使用时,子类可以重写父类来自己实现该方法的功能。 方法重写的注意事项
子类重写父类方法后,调用方法不在调用父类的方法,而是调用子类重写后的方法
子类重写父类方法时,使用的权限修饰符要大于等于父类方法的权限
Public > protected > 默认 > private
父类private修饰的方法不能被子类重写,即使子类有完全相同的方法也不属于重写,属于重新定义一个新方法
静态方法可以被继承但不能被重写,如果父类中的定义的静态方法在子类中被重新定义,那么在父类中定义的今天方法将被隐藏。可以使用语法"SuperClassName.staticMethodName"调用隐藏的静态方法
12. 访问控制修饰符
实现封装,暴露与隐藏---保护数据的安全
封装类型
public:公开的,任何类
protected:受保护的,本类、派生类、同包类
默认的:什么也不写,本类、同包类
java不建议
private:私有的,本类
类的访问权限只能是
public
默认的
类中成员的访问权限如上四种都可以
13. static:静态的
静态变量
public class StaticDemo { public static void main(String[] args) { Eoo o1 = new Eoo(); o1.show(); Eoo o2 = new Eoo(); o2.show(); Eoo o3 = new Eoo(); o3.show(); System.out.println(Eoo.b); //常常通过类名点来访问 } } class Eoo{ //演示静态变量 int a; static int b; Eoo(){ a++; b++; } void show(){ System.out.println("a="+a+",b="+b); } }
由static修饰
属于类,存储在方法区中,只有一份
常常通过类名点来访问
何时用:所有对象所共享的数据(图片、音频、视频等)
静态方法
package ooday04; //static的演示 public class StaticDemo { public static void main(String[] args) { Eoo o1 = new Eoo(); o1.show(); Eoo o2 = new Eoo(); o2.show(); Eoo o3 = new Eoo(); o3.show(); System.out.println(Eoo.b); //常常通过类名点来访问 Goo.plus(4,6); Hoo o4 = new Hoo(); Hoo o5 = new Hoo(); Hoo o6 = new Hoo(); } } //演示静态方法 class Foo{ int a; //实例变量(由对象来访问) static int b; //静态变量(由类名来访问) void show(){ //有隐式this System.out.println(this.a); System.out.println(Foo.b); } static void test(){ /*静态方法中没有隐式this传递 没有this就意味着没有对象 而实例变量a是必须由对象来访问的 所以下面的语句发生编译错误*/ //System.out.println(a); //编译错误 System.out.println(Eoo.b); } } class Eoo{ //演示静态变量 int a; static int b; Eoo(){ a++; b++; } void show(){ System.out.println("a="+a+",b="+b); } }
由static修饰
属于类,存储在方法区中,只有一份
常常通过类名点来访问
静态方法没有隐式this传递,所以不能直接访问实例成员
实例变量前一定是用对象来访问,this. 访问
静态变量前用类名打点,Foo. 访问
静态方法不能访问实例变量
何时用:方法的操作与对象无关
public static void main(String[] args) { Goo.plus(4,6); //调用静态方法只需要类打点就行。 } //演示静态方法何时用 class Goo{ int a; //对象的属性 //方法中用到了对象的属性a,意味着show()的操作与对象是有关的,不能做成静态方法 void show(){ System.out.println(a); } //方法中没有用到对象的属性和行为,意味着plus()的操作与对象是无关的,可以做成静态方法 static void plus(int num1,int num2){ int num = num1+num2; System.out.println(num); } }
静态块
//演示静态块 class Hoo{ static { System.out.println("静态块"); } Hoo(){ System.out.println("构造方法"); } } //演示静态方法何时用 class Goo{ int a; //对象的属性 //方法中用到了对象的属性a,意味着show()的操作与对象是有关的,不能做成静态方法 void show(){ System.out.println(a); } //方法中没有用到对象的属性和行为,意味着plus()的操作与对象是无关的,可以做成静态方法 static void plus(int num1,int num2){ int num = num1+num2; System.out.println(num); } }
由static修饰
属于类,在类被加载期间自动执行,一个类只被加载一次,所以静态块也只执行一次
何时用:初始化/加载静态资源(图片、音频、视频等)
成员变量分两种
实例变量:没有static修饰,属于对象的,存储在堆中,有几个对象就有几份,通过引用打点来访问
在构造方法中给实例变量做初始化
静态变量:有static修饰,属于类的,存储在方法区中,只有一份,通过类名打点来访问
在静态块中给静态变量做初始化
内存管理:由JVM来管理的
堆:new出来的对象(包括成员变量)
栈:局部变量(包括方法的参数)
方法区:.class字节码文件(包括静态变量、所有方法)
14. final
最终的,不可改变的-----------单独应用几率低
修饰变量:变量不能被改变
修饰方法:方法不能被重写
修饰类:类不能被继承
static final常量:应用率高
必须声明同时初始化
通过类名点来访问,不能被改变
建议:常量名所有字母都大写,多个单词用_分隔
编译器在编译时会将常量直接替换为具体的值,效率高
何时用:数据永远不变,并且经常使用
15. 抽象类
抽象方法:
由abstract修饰
只有方法的定义,没有具体的实现(连{}都没有)
抽象类:
由abstract修饰
包含抽象方法的类必须是抽象类
方法抽象,类一定抽象
抽象类不能被实例化(new对象)
抽象类是需要被继承的,派生类:
重写所有抽象方法--------------变不完整为完整
也声明为抽象类------------------一般不这么做
抽象类的意义:
封装共有的属性和行为--------------------代码复用
为所有派生类提供统一的类型-----------向上造型---代码复用
可以包含抽象方法,为所有派生类提供统一的入口(能点出来)
派生类的行为不同,但入口是一致的,同时相当于定义了一个标准
16. 内部类
成员内部类
应用率低,了解
类中套类,外面的称为外部类,里面的称为内部类
内部类通常只服务于外部类,对外不具备可见性
内部类对象只能在外部类中创建
内部类中可以直接访问外部类的成员(包括私有的),在内部类中有个隐式的引用指向了创建它的外部类对象------外部类名.this
匿名内部类
应用率高-----------------大大简化代码
若想创建一个类(派生类)的对象,并且对象只创建一个,此时该类不必命名,称为匿名内部类
匿名内部类中不能修改外面变量的值,因为在此处该变量默认为final的
每一个类都会有独立的.class字节码文件
17. 接口:
1. 类和类------------------------继承extends 接口和接口------------------继承extends 类和接口---------------------实现implements 2. 设计规则: - 将所有派生类所共有的属性和行为,抽到超类中-------------抽共性 - 派生类的行为都一样,则设计为普通方法 派生类的行为不一样,则设计为抽象方法 - 将部分派生类所共有的属性和行为,抽到接口中 接口是对继承的单根性的扩展---------------实现多继承 符合既是也是原则时,应使用接口 3. 可以向上造型为:超类+所实现的接口
是一种引用数据类型
由interface定义
只能包含常量和抽象方法------默认权限是public
接口不能被实例化
接口是需要被实现/继承,实现/派生类:必须重写所有抽象方法
一个类可以实现多个接口,用逗号分隔
若又继承又实现时,应先继承后实现
接口可以继承接口
接口的意义:
封装部分派生类共有的属性和行为,实现多继承
制定了一个标准,一种规范
18. 多态:
表现:同一个对象被造型为不同的类型时,有不同的功能,对象的多态:我、你、水......------所有对象都是多态的
同一类型的引用指向不同的对象时,有不同的实现
行为的多态:cut(),move(),getImage()--所有抽象方法都是多态的
向上造型/自动类型转换:--------------------代码复用
超类型的引用指向派生类的对象
能点出来什么,看引用的类型
能造型成为的数据类型有:超类+所实现的接口
强制类型转换,成功的条件只有如下两种:
引用所指向的对象,就是该类型
引用所指向的对象,实现了该接口或继承了该类
强转时若不符合如上条件,则发生ClassCastException类型转换异常
建议:在强转之前先通过instanceof来判断引用的对象是否是该类型