1 面向对象No6
面向对象 OO Object Oriented
编程时以对象为单元,封装数据和逻辑,以此提高软件的重用性、扩展性
类 对象
类是对象的模板、对象是类的实例
辨别对象是否是类的实例:对象isa 类
(javac*.Java表示编译当前路径下的所有java文件)
Java定义一个类:
[修饰符] class类名{
}
使用定义好了的类创建一个对象
new 新建
new 类名() 新建一个类的对象
(成员变量,申明在类体中的变量,注意不要和申明在方法中的局部变量混淆),如人类的年龄、体重、身高
[修饰符] class 类名{
[修饰符] 类型 属性名 [=初值];
}
如果属性不赋值,默认的大小(在对象创建时赋默认值):
int类型为0
double类型为0.0
boolean 为false
属性可以在申明时同时赋初值(在对象创建时赋默认值)
(局部变量在使用前必须要初始化、而属性在使用前可以不显式初始化)
(局部变量的作用范围、生命周期在方法内、属性的生命周期随对象的生命周期,对象产生则属性产生,对象销毁则属性销毁)
(局部变量在栈内存中分配、成员变量在堆内存中分配)
通过对象使用属性:
(引用名/对象名).属性名
这样可以对属性进行赋值和使用
描述类的行为,可以将运算逻辑封装其中,在适当的时候调用
定义一个方法(非静态)
[修饰符] class 类名{
[修饰符] 返回类型 方法名(类型 参数1,类型 参数2...){
}
}
方法的调用:(调用时参数个数、类型、顺序要和定义时一致)
对象.方法名(参数1,参数2...)
(可以通过方法去改变对象的属性)
访问权限修饰符
public 公有,任何地方都可以使用
private 私有,只有在本类中可以使用,可以用来隐藏属性、隐藏具体的细节
如果属性申明为私有,可以使用公有的方法将其向外暴露,getter方法和setter方法,这是一种简单的封装
(面向对象三大特征:封装、继承、多态)
封装:隐藏细节,将需要的内容对外暴露;可以增强代码的安全性、一致性、易用性
构造方法:对象在被构造、创建时会调用的方法,一般进行初始化工作
[修饰符]方法名(参数列表){
}
注意事项:
1、方法名必须和类名一样
2、没有返回类型
3、实参和形参要匹配
4、如果一个类没有定义构造方法,会隐式拥有一个无参构造方法
5、如果写了自定义的构造方法,那么隐式的无参构造方法就没了
6、构造方法可以重载,条件是同名、不同参
7、属性的默认赋值在构造方法之前
1、引用=对象表示引用指向这个对象
2、 引用.方法() 表示调用引用所指向的对象的方法(属性也如此:引用.属性)
3、引用1 =引用2引用1指向引用2所指向的对象,或者说引用引用1和引用2指向同一对象
引用
除了8种基本数据类型以外,其他都是引用数据类型
1、引用 = new 类() 将引用指向新建的对象
2、引用.方法()调用引用所指向的对象的方法(属性也如此)
3、引用=另一个引用,两个引用指向同一个对象
(引用的本质是存放对象的首地址的空间
引用=对象就是把对象的首地址放到引用中保存
引用.方法()引用.属性则是根据引用中保存的地址找到对应的对象
并调用它的方法或属性
引用1 =引用2就是将引用2所保存的地址拷贝给引用1)
【
成员变量在堆内存中开辟空间,生命周期跟所属对象一致,用来存储数据
局部变量在栈内存中开辟空间,生命周期在方法中所在语句快中
】
两个引用数据类型变量互相用=赋值,使用.改变其中一个,另一个受影响
不用了的(堆)内存/对象,自动进行回收
如何判断一个对象不会再被使用:
如果一个对象,没有一个引用指向它,那么它就被系统判断为不会再被使用(垃圾内存)
System.gc()可以提示系统去进行垃圾回收,但不会马上进行,系统会根据实际情况在适当时刻执行
【内存垃圾回收机制是通过判断一个对象是否有引用指向它,如果没有一个引用指向这个对象,这个对象就会被标识为垃圾对象,在合适的情况会被回收。】
1、基本数据类型参数,方法内对形参进行赋值,不会影响到方法外的实参变量
2、引用数据类型参数,方法内对形参指向的对象进行.操作《=》,方法外实参所指向的对象会受到影响(因为实参和形参指向同一个对象)
引用= null表示不指向任何对象或者说不记载任何对象的首地址,
这种情况下,通过引用.属性或引用.方法()进行操作会产生空指针。
1、 使用this.变量名可以分辨一个类中同名的属性和局部变量,有this.的变量为属性。
【this.成员变量,可以用来区分同名的成员变量和局部变量】
2、 this.后面也可以跟方法,但是一般很少这样用(调用本对象的另一个方法,一般省略。)
3、 this也可以单独使用
4、 this作为返回值用,在方法中 return this
5、 this 作为实参用,比如:setOnClickListener(this)
二:可以用来表示同一个对象的构造方法
this(参数1,参数2) 这样写表示调用同一个类的重载构造方法
注意:
1、在一个构造方法中调用另一个构造方法,必须要在第一句
2、在一个构造方法中只能有一个this(….)
3、 只有构造方法才能通过this(…)调用构造方法,不能再方法中调用构造方法
静态(修饰符),可以修饰属性、方法
【1、static修饰成员变量,称为静态变量:静态变量只存在一份拷贝/
类名.变量名《用对象.变量名也行,但会有警告。》
】
一、静态属性
[其他修饰符] static 类型 属性名 [= 默认值];
(如果引用数据类型不显式指定,默认值为null)
1、无论这个类产生多少个实例,静态属性都只存在一份拷贝
2、调用方法:应该通过类名.静态属性名来调用、访问静态属性
(也可以使用对象.静态属性名,但不推荐)
(实际使用:静态常量、单例模式)
二、静态方法
【
1、 静态方法跟着类,非静态方法跟着对象,要用静态方法: 类名.方法名
2、 静态方法中访问非静态属性?非静态方法?使用this?
在静态方法中不能访问非静态属性,不能调用非静态方法,不能用this
3、 无论哪里都可以访问静态变量和方法
4、 同一个类中调用静态属性和方法可以省略类名.
(同一个类中调用非静态方法和属性可以省略this)
】
三、static修饰代码块称为静态代码块
在类体中
Static{
./……
}
是在类被载入时调用的,一次应用程序只会调用一次静态代码块
[其他修饰符] static 返回类型 方法名(参数列表){
}
1、静态方法应该通过类名来调用(对象也可以,但不推荐)
2、在静态方法中不能使用this,不能访问非静态属性、非静态方法,可以访问静态属性、静态方法
3、在非静态方法中可以直接访问本类静态方法、静态属性、非静态方法、非静态属性(简单说就是都可以)
用来区别类,类的全名=包名.类名
如何指定类的包名:
package包名; (包名为xx.xx.xx,一般命名规则为域名倒过来写,比如域名为qianfeng.com,包名就是com.qianfeng)
为了区分不同的类,包名.类名才是完整的类名
Jvav常用包:
【
Java.util 工具包
Java.math数学包
Java.lang java语言包,这个包下的类不需要导入
】
如何导入:
import包名.类名;//导入指定类
import 包名.*; //导入这个包下所有的类
(ctrl + shitf + o 自动导入)
java.lang下的类不需要导入
同一个包下的类不需导入
权限修饰符:
【
public:修饰方法、成员变量,表示在任何地方都可以访问
private:私有的,修饰方法、成员,表示只有在本类才能用
往往用private 修饰类中成员变量,用public 修饰方法,以达到封装的目的
封装是面向对象的一大特点:
将数据隐藏,同过方法以一定形式向外呈现可以提高代码的安全性、一致性。
】
将数据和逻辑封装在类中,调用者只需要去使用,而不需要关注其中的数据和具体的逻辑。
优点:是使用起来方便,更重要的是分离了调用和具体数据、逻辑,使代码耦合度更低。
this除了当前对象,还可以用于同类中构造方法的调用
this(...);
增强代码重用性、降低耦合、降低开发风险
注意:
1.this(...)必须是构造方法中的第一条语句
2.不能再同一构造方法中使用两次this(...)
【继承(面向对象又一特点)
继承表示类和类之间的关系,一个类继承另一个类,就自动拥有了那个类的属性和方法
还可以在这个基础上扩展(继承现有的,拓展自身的)
继承关系可以用子类 is 父类
继承另一个类的类称为子类;被继承的类称为父类。
例子: 父类 子类
电脑 笔记本电脑
车 卡车
继承的语法:在定义一个类时可以将其声明成另一个类的子类
[修饰符] class 类名extends父类名{
}
注意:
1、继承是类和类的关系
2、一个父类可以有多个子类
3、一个子类只能有一个父类
4、可以进行层次化的的继承,子类可以从父类、爷爷类那里继承属性和方法
】
【
可以在子类中定义属性、方法,来进行扩展
重写(覆盖)
子类中定义和父类方法同名、同参数列表、同返回类型的方法,称为方法的重写。
方法的重写:
可以使用super关键字,调用父类的方法逻辑
Super.方法名(……);
使用以上方式重用父类的逻辑,可以减少重复代码,降低软件的耦合度。
(
1:子类重写的方法不能有比父类更严格的访问权限,比如父类public的方法被子类重写成private
2:子类不能比父类抛出更多的异常
3:静态方法重写静态方法,非静态方法重写非静态方法
)
】
【
重载:overload《同一个类中同名不同参》
重写: override《子类和父类同名同参同返回》
】
【
Super 超类、父类
一、表示父类
1、 super.方法()调用父类的方法
2、 super.属性访问父类的属性(一般不用,因为一般子类不会去覆盖父类的属性)
二、调用父类的构造方法
Super(……)
注意:
1、 必须在构造方法中调用
2、 必须是所在构造方法的第一句,不能调用两次
3、 如果在子类的构造方法中不显式调用父类的构造方法,则会隐式调用父类的无参构造方法super()
】
一个类(子类)继承另一个类(父类)的属性和行为,并进行扩展
比如:Student类是Human类的子类,继承了Human的年龄,体重、chifan、睡 觉等属性,行为,并且扩展了年级属性、学习行为
一个父类可以有多个子类,比如Human类可以有Student这个子类,还可以有 Teacher类等其他子类,但一个子类只能有一个父类,单继承(和C++不同)
继承可以层次化继承
比如:人类是父类,但它同时也可以是动物类的子类
判断一个类是否是另一个类的子类,可以用is,比如
人is动物,学生is人
如何在Java中使用继承:
extends(扩展):继承的关键字
[修饰符] class 类名 extends 父类名{
}
这样就可以定义了一个子类,继承父类
为什么要继承:
1.重用父类的属性和方法,在需求变更时只需要更改父类代码
2.继承如果结合多态、反射,可以大大降低软件的耦合度,便于扩展
权限方法修饰符:
除了private、public外
有protected:本类中、同一包中、子类中可以访问
还有 不写(default):本类中、同一包中可以访问
修饰符 同一个类中 同一个包中 子类中 全局
private √
default √ √
protected √ √ √
public √ √ √ √
重写(覆盖):
子类在继承父类的行为的情况下,有一部分行为和父类不一样,称之为重写
如何进行重写:
1.子类继承父类
2.子类中定义和父类一样的方法(同名,同参数列表,同返回类型),那么这个方法就重写(覆盖)了父类中的相应的方法
重写的应用:Android中组件的使用以及Servlet中的HttpServlet的应用,都是使用 了继承+重写,可以重用这些框架中大部分的默认功能,只将小部分 的逻辑、行为进行重写、自定义,使得框架按照我们自己的意愿去运 行
注意事项:
1.子类重写的方法不能比父类有更严格的访问权限
2.子类重写的方法不能抛出比父类方法更多的异常
3.静态方法重写静态方法,非静态方法重写非静态方法
super父类(父类“对象”)
1.可以用来调用父类中定义的方法
super.父类方法名(...)
可以降低代码间的耦合度,降低开发的风险
2.可以用来调用父类属性(父类的属性和子类属性同名,可以用super来指定父类属 性)
super(...)表示调用父类的构造方法
1、只能在构造方法中调用,只能在第一句,并且在一个构造方法中只能调用一次
2、如果一个子类构造方法没有显示调用super(...),则会隐式调用super()调用父类无参的构造方法;如果父类没有无参构造方法,而子类构造方法又没有显示调用super(...),编译会出错
代码块:
在类中直接写
{
代码
}
其在对象创建时会被调用,并且在构造方法调用之前
如果是父子类都有构造方法和代码块,那么顺序是:
父类代码块-》父类构造方法-》子类代码块-》子类构造方法
静态代码块:
在类中直接写
static {
代码
}
其在类被载入时(在对象创建之前)调用,在应用程序结束前只会被调用一次
权限修饰符:
【
public 哪里都可以访问
private 本类中才可以访问
又想隐藏封装,又想让子类用,就用protected 主要修饰成员变量和方法
(构造方法可以用private修饰,在其他类中不能new 这个类了class 前用public表示
这个类是主类,必须和文件名相同,class前用public 表示这个类是主类,必须和文件名相同,一个文件中只能有一个主类,public的类可以被其他包中的类访问。)
】
聚合、组合关系【
】
【alt + shift +r:重命名】
【java中所有的类都是Object的子类(直接或间接),如果一个类不显式继承任何类,那么它会隐式继承Object类】
Object(物体、东西),这个类是所有类的父类,创建一个类,这个类会自动继承 Object
Object主要方法:
1. booleanequals(Object o)判断当前对象和参数传入的对象是否相等
2. 【判断调用这个方法的对象和参数传入的对象是否相等】
引用1==引用2如果两个引用指向同一个对象,返回true,否则返回false
【
==判断引用数据类型,判断的是两边的引用是否指向同一对象
(本质是判断两个引用中藏着的地址是否相同。)
Object类的equals方法的默认逻辑仍然是==的逻辑,比较两个引用是否指向同一对象
如果想用自己的逻辑去比较,就需要重写equals的逻辑相同返回true不同返回false
】
【
publicbooleanequals(Objectobj){
Triangler= (Triangle)obj;
returnthis.a==r.a&&this.b==r.b&&this.c==c;
}
】
Object类的equals方法的默认逻辑是比较当前对象和参数引用指向的对象是否是同一个对象
2.Class getClass()返回这个对象的描述类对象
3. inthashcode()返回这个对象的哈希码
【可以认为这个返回调用的对象的哈希码值,可以认为这个返回的哈希值是当前对象的首地址】
哈希码本质上是引用所指向对象的地址经过一定的转换得到的数值,一般情况下,可以使用哈希码来判断是否是同一个对象
4. StringtoString返回表示这个对象的字符串形式
【Object类的默认toString()方法返回一个字符串,包括3部分,第部分是当前对象的全名
第二部分是@字符第三部分是哈希码
这个字符串没什么用,一般需要重写其逻辑,让其返回我们需要的信息】
默认的值是全类名加上@再加上hashcode()的十六进制形式
这样的信息一般没什么用,要在子类对象调用时返回有效信息,就需要重写这个toString()方法,并在其中写上自定义的逻辑
【Class getClass()返回对象的描述类对象(对象模板,返回图纸)】
抽象类、抽象方法
【抽象类:有些类并不能确认行为(方法逻辑),可以将其声明为抽象类
一般在抽象类中有一个到多个抽象方法(也可能没有)
:抽象方法没有方法体
:抽象类不能实例化,要使用抽象类,先要用一个类继承它,并实现其所有的抽象方法,然后再实例化这个子类。
】
abstract抽象关键字
[修饰符] abstract class类名{
[修饰符] abstract返回类型方法名(参数列表); //抽象方法定义
}
【
抽象类的使用:
抽象类不能直接实例化,要使用抽象类,先要用一个类继承它,并实现其所有的抽象方法,然后再实例化这个子类。
注意:
1、抽象类中可以没有抽象方法
2、抽象类中可以定义非抽象的方法、属性、构造方法(可以通过子类调用)
3、如果一个类继承了抽象类,但没有实现所有的抽象方法,那么这个子类就必须声明成抽象的。
4、如果一个类中有抽象方法,那么这个类肯定要声明为抽象的
】
1.抽象类中可以有非抽象方法、属性、构造方法,一般情况下,至少有一个抽象方法(可以没有抽象方法)
2.抽象类不能直接实例化,用一个子类去继承抽象类并且实现它的所有的抽象方法,这个子类就可以实例化
3.如果一个类继承了抽象类,但没有实现所有的抽象方法,那么这个类仍是抽象类
抽象类模板模式:将可能需要自定义的部分留空,让使用者去实现,和普通继承差不多,只是强调让实现者写上自己的逻辑
(抽象方法不能为private、static、final)
final可以修饰变量、类、方法
【
final最终:
1、变量表示这个变量的初始化后不能修改
(1)基本数据类型值不能改
(2)引用数据类型引用指向一个对象后不能再指向另一个对象
2、修饰方法:表示这个方法不能被重写
3、final修饰类,表示这个类不能被继承
】
1、final 表示常量,在申明后只能赋值一次(一般常量名全部大写,一般也申明为static)
2、final 修饰类,表示这个类不能被继承
3、final 修饰方法,表示这个方法不能被重写
100%具体0%~100%具体0%抽象
类抽象类接口
接口:可以通过它将不同的软件部件组装起来
【
接口完全抽象的,里面只有抽象方法(还能有静态常量)
接口的使用:
不能直接实例化
要定义一个类实现这个接口,并实现其所有的抽象方法,才能将这个类实例化
:1、多个类可以实现同一个接口
:2:、一个类可以实现多个接口(一个类只能有一个父类),实现的语法是implements关键字后写多个接口,之间用逗号,隔开,这个类如果要实例化,要将这多个接口的抽象方法都实现掉。
:3、如果一个类实现接口,但没有实现所有的抽象方法,那么这个类仍然要定义成抽象类。
4、接口可以继承接口(用extends关键字),可以多继承。
5、接口中出了抽象方法还可以定义final static的成员变量(静态常量)
】
关键字:interface
定义一个接口:
[修饰符] interface接口名{
[修饰符]返回类型方法名(参数列表);
}
1.接口中可以定义方法,都是抽象方法,没有方法体,只允许public和abstract,可以不写(和写一样)
2.接口中还可以定义常量(final属性)
接口不能直接实例化,要实例化,需要用一个类去实现它,并实现所有的抽象方法,才能将这个实现的类实例化
实现方法:
[修饰符] class 类名 implements 接口{
在这里实现所有的抽象方法
}
之后可以将实现的类进行实例化
1.多个类可以实现同一个接口
2.一个类可以实现多个接口
[修饰符] class 类名 implements 接口1,接口2,接口3,...{
}
3.一个类实现了一个接口,但未实现其中的所有抽象方法,那么这个类应该被申明为抽象类
4.接口可以继承接口,并且接口的继承可以多继承
对修改关闭,对扩展开放
多态:【
父类的引用指向子类的对象(包括抽象类的继承、也包括接口的引用指向实现类的对象)
Animal a = newHuman();
Human h= newStudent();
Student s = newHuman();
注意:
1、父类的引用调用重写方法时,调的是子类的方法
2、父类的引用访问重写属性时,访问的是父类的属性
】
多态的引用:
【
1、应用于方法的参数
2、应用于方法的返回类型《简单工厂模式》
3、应用于类的属性
】
多态:父类的引用指向子类的对象(接口引用指向实现类对象)
向上转型(自动转,不用强转)
向下转型(需要强转,让我们确认)《在继承层次图中向下、子类转,需要强转,方式是在前面加上(要转成的类型)
如:Animal a = newAnimal();
Cat c = (Cat)a;//将一个动物强转成猫
【
这样强转可能会失败,也可能会成功,关键是看原来那个引用指向的是不是要强转成的类型,比如:
Animal a =new Cat();
Cat c =(Cat)a; //这样的强转会成功,因为a本来就指向一只猫
】
可以使用关键字instanceof来判断一个引用是否指向某一类型对象:
用法:
引用名instanceof类名
如果这个引用指向的对象是这个类型,就返回true否则返回false
》
多态的应用:多态结合:
1.参数传递
2.属性的设置
多态中,父类的引用不能直接调用子类对象自己的方法,如果要调用,先要进行向下转型
引用 instanceof 类型,判断一个引用是否是某个类型的实例,是的话,返回true,否则,返回false,常常在向下转型之前进行判断,避免出现ClassCastExpection
内部类:
定义在另一个类内部的类
1.成员内部类
【内部类定义在外部类的类体中,修饰符中没有static
特点:
1、成员内部类对象持有外部类对象的引用
或者说一个成员内部类对象必须依附于一个外部类对象
2、在成员内部类的方法中,可以直接外部类的属性,可以直接调用外部类的方法
3、在内部类的方法中使用this,表示的是内部类的当前对象;要访问外部类的当前对象,要用外部类名.this
】
直接在另一个类的类体中定义,不加static
(1)成员内部类持有外部类的引用(每个内部类对象依附于一个外部类对象),所以可以直接访问外部类的属性和方法
(2)创建成员内部类:如果在外部类中创建,可以直接new;如果不是在外部类中,那么就不能直接new,需要:
先创建外部类对象,然后
外部类对象.new内部类()
(3)在成员内部类中,要表示外部类的当前对象(引用),使用:
外部类名.this.
2.静态内部类
【静态内部类定义在外部类的类体中,修饰符中有static
特点:
1、静态内部类对象不持有外部类对象的引用,或者内部类对象不依附于外部类对象
2、在静态内部类的方法中,不能直接访问外部类的属性,不能直接调用外部类的方法(这里指的是非静态的,静态的可以。)
3、在静态内部类的方法中,根本不能使用this
4、创建静态内部类的方式:new外部类名.内部类名()
】
直接在另一个类的类体中定义,加static
(1)静态内部类不持有外部类的引用(内部类对象不依附于外部类对象),不能直接访问外部类的非静态属性和方法
(2)创建静态内部类:即使在外部类外部,也可以直接创建(但要指定内部类所在外部类的类名)
(3)静态内部类可以访问外部类的静态属性、调用静态方法
3.局部内部类
【局部内部类定义在外部类的方法体中
1、定义好以后只能在所定义的那个方法中使用
2、局部内部类中不能访问所在方法的局部变量(JDK1.8之前)
】
在方法中定义的内部类
(1)不能访问外部类方法的局部变量
(2)可以访问外部类的属性
(3)只能在定义内部类的那一个外部类方法中实例化
(匿名内部类可以同时是局部内部类)
4.匿名内部类
【没有名字的内部类,可以在一句语句中完成类的定义、继承(实现)以及实例化
new父类(){
方法重写【实现】
};
//在这句中,首先定义了一个匿名类,继承父类,并在大括号中重写父类的方法
//然后创建一个这个匿名类的实例
New接口(){
方法实现
};
//在这句中,首先定义一个匿名类,实现接口,并在大括号中实现抽象方法,
//然后创建一个匿名类的实例
:匿名内部类可能同时是局部内部类,就不能访问访问所在方法局部变量
】
是一种简写方式,可以同时继承(实现)和实例化,继承(实现)后的类没有类名
new 父类或接口 () {
重写或实现的方法
};
这样可以实例化继承父类或实现接口的那个匿名类,在继承或实现时,可以在{}中写上重写或实现的具体逻辑
回调:不是由自己调用方法,而是自己写,但由框架、系统来调用