前言
学习面向对象的三大主线: 1.Java类及类的成员:属性、方法、构造器;代码块、内部类 2.面向对象的三大特性:封装、继承、多态 3.关键字:this、super、instanceof、static、final、abstract、interface、implements、package、import等。
一、面向对象说明、内存解析
面向对象说明
面向对象:谁来做,将功能封装到对象,具备功能的对象
核心概念:类和对象
类:一类事物,比如抽象概念的人
对象:一类事物的实例,实实在在的人
重点:类的成员设计
属性:成员变量
行为:成员方法
使用:
1.创建类,设计类的成员
2.创建类的对象
3.调用:对象.属性、对象.方法
内存解析
对象内存解析:
Person p1 = new Person();
Person p2 = new Person();
Person p3 = p1;
//说明:
1.new出来的每个对象都有独立的属性
2.p3没有new 创建新的对象
3.那么p3和p1共用同一个堆空间对象,即两个人数据相同
4.无论修改p1,还是p3 ,它们的属性都会改变
如:p3.age=1;那么p1.age 也等于1
java内存解析:
1.java源代码>编译>生成字节码文件.class>运行
2.使用jvm类的加载器和解释器对生成的字节码文件进行解释运行
3.即将字节码文件对应的类加载到内存,涉及到内存解析
虚拟机栈:局部变量 ( = 左边变量名)
堆:右边 new 的对象及属性
方法区:类的加载信息 main方法、常量池、静态域
二、属性和方法
属性
属性(成员变量)VS 局部变量
相同点:
1.定义格式:数据类型 变量名
2.先声明,后使用
3.都有对应的作用域
不同点:
1.声明位置不同
成员变量:类中
局部变量:方法、构造器、代码块、形参
2.权限修饰不同
成员变量:可以使用权限修饰符
局部变量:不可以
3.默认初始化不同
成员变量:都有初始化值
局部变量:没有初始化值,调用时需赋值
4.内存中加载位置不同
成员变量:加载到堆中
局部变量:加载到栈中
方法
声明:权限修饰符 返回值类型 方法名(形参){方法体}
注:static、final、abstract 都可修饰方法
权限修饰符:private、public、protected、default
返回值:void(无返回值)、其它数据类型(有返回值,需要return)
return关键字:
使用范围:方法体中
作用:1.结束方法 2.针对有返回值的方法,用return返回所需数据
形参:可有可无
注:
1.方法使用中,可以调用当前类的属性和方法
2.特殊:方法调用其本身,被称为递归方法
3.方法中不能定义方法
三、匿名对象 和 方法重载
匿名对象
匿名对象:只能调用一次,一般作为参数使用
比如:void 方法名(Phone phone),调用此方法时可写成 ph.方法名(new phone())
比如:new phone().方法名() // 使用后此对象就被释放
抽象类的匿名子类、匿名对象:(这里很绕,建议先看 十五章abstract抽象关键字)
匿名子类的非匿名对象:
Person person = new Person(){子类重写父类方法};
// Person person :代表非匿名对象
// new Person():代表 匿名
//{子类重写父类方法}:代表子类
匿名子类的匿名对象:
new Person(){子类重写父类方法}
// 对比 匿名子类的非匿名对象
方法重载
说明:同一个类中,定义一个以上的同名方法,但它们的形参不同
判断是否属于重载:跟权限修饰符、返回值类型、形参变量名、方法体无关
即就算它们不同,只要方法名相同,参数列表的类型、数量相同,就是重载
调用重载方法:根据参数列表调用
四、方法参数的值传递机制、可变个数形参
方法参数的值传递机制
参数种类:
形参:方法声明时的参数
实参:调用方法时,实际传给形参的参数值
java中的实参如何传递给方法?
java中的参数传递机制只有一个:值传递
即将实参的副本传给方法,参数本身不受影响
形参是基本数据类型:将实参的值 传递给形参
形参是引用数据类型:将实参的地址值 传递给形参
可变个数的形参:数据类型…变量名
说明:
1.当调用可变个数形参的方法时,传入的参数可以是任意个数
2.必须声明在形参的最后一个
3.只能声明一个
4.本质是数组
public void show(String ... strs){
system.out.println("show(String...strs)")
for(int i=0;i<strs.length;i++>){
system.out.println(strs[i])
}
}
test.show(new String[]{"AA","BB"})
--------------------------------------------------------
五、封装
设计思想:隐藏内部的复杂性,只对外开放简单的接口,从而提高代码的可扩展、维护性
使用:
private int age;
public int getAge(){return age;}
public void setAge(int age){this.age=age;}
设计追求:高内聚,低耦合
高内聚:类的内部数据操作细节字节完成,不允许外界干涉
低耦合:仅对外暴露少量的方法用于使用,或者说是低依赖性
封装体现:需要权限修饰符,将类的属性私有化,提供get/set,设置获取属性的值
六、构造器
作用:创建对象、初始化对象属性
格式:
public 类名(形参){ }
说明:
1.任何一个类都有构造器
2.系统会默认送一个空的构造器,如果自己写了,系统就不送了
3.一个类可以有很多构造器:重载即可
4.一个类至少有一个构造器
七、权限修饰符 和 this、package、import关键字
权限修饰符
四种(范围从小到大排序):private、缺省default、protected、public
用途:修饰类、属性、方法、构造器、内部类
注:修饰类,只能使用 public 或 default
this、package、import关键字
this 说明:
1.可以修饰:属性、方法、构造器
2.修饰属性和方法:代表当前对象 / 正在创造的对象 / 调用它的对象
3.一般形参和属性名同名时使用,其它情况可省略不写this
4.使用this调用构造器:
当构造器中有重复代码,可以使用this() 或 this(形参) 来调用指定构造器
注:必须声明在首行,且只能声明一个,不能调用自己
package 说明:
1.声明类和接口所在的包,声明在源文件首行
2.包名全小写,每.一次,代表一层目录
3.同一个包下,不能命名重名
import 说明:导入包,自动导入
----------------------------------------------------
八、继承:extends
格式:public class 子类名 extends 父类名{}
继承体现:
1.继承父类中的属性和方法
2.子类可以声明自己特有方法
继承优点:
1.减少代码冗余,提高代码复用性
2.便于扩展功能
3.为多态使用,提供前提
注:java只支持单继承和多层继承,不支持多继承
1.一个子类只能有一个父类,一个父类可以有很多子类
2.有直接继承(直接父类)、间接继承(间接父类)
3.子类继承所有父类的属性和方法
>所有父类:直接父类+间接父类
>间接父类:父类的父类
4.Object类 是所有类的父类
九、重写
说明:子类继承父类后,在子类中对父类的同名同参方法进行重写覆盖
>重写后,子类对象调用父类中的同名同参方法时,实际执行的是子类中重写后的方法
规定: 重写方法(子类中的方法)、被重写方法(父类中的方法)
1.子类重写父类方法,要求方法名和参数相同
2.子类重写的方法 权限修饰符,范围不能小于父类被重写的方法
>注:子类不能重写父类的private方法
3.返回值类型:
>父类是void,子类必须是void
>父类的返回值是A类型,子类的返回值可以是A类型,也可以是A类型的子类
>父类是基本数据类型,子类必须是基本数据类型
4.子类抛出的异常类型,不大于父类被重写方法的异常类型
5.子类和父类中同名同参方法要么都声明为 非static ,要么都声明static
>注:声明static 不叫重写,且父类的static方法,一定不能被重写
十、super关键字 和 子类对象实例化过程
super关键字
说明:
1.super:父类的...
2.可以调用父类的属性、方法 : super.属性/方法
3.调用父类的构造器: super();
何时使用:
1.属性名相同,但意思不同
2.方法被重写时,需要用到父类的方法体
3.在构造器中,super()和this(),只能二选一,如果不选,默认 super()
子类对象实例化过程
说明:
1.子类继承父类后,就获取了父类的属性和方法
创建子类对象,在堆空间,就会加载所有父类中声明的属性
2.子类通过构造器创建对象时,一定会直接或间接的调用其所有父类的构造器,直到Object类空参构造
3.正因为加载了所有父类结构,才可以看到内存中所有父类中的结构,子类对象才可以考虑调用
注:子类创建对象时,虽然调用了所有父类的构造器,但它只创建一个对象,就是子类的对象
--------------------------------------------
十一、多态 和 instanceof关键字
多态
格式:父类 对象名 = new 子类();
使用说明:虚拟方法调用
1.子类中定义了和父类同名同参的方法,在多态情况下,父类方法就叫虚拟方法
2.父类根据不同的子类对象,动态调用属于子类的该方法
注:多态在编译时只能调用父类中声明的方法,运行时调用的是子类中重写的方法
总结:编译看左,运行看右
>如果它不是晚绑定,它就不是多态
>方法调用那一刻,解释运行器才会确定自己所要调用的具体方法
多态使用前提:1.继承关系 2.方法重写
为什么使用多态:没有多态性,抽象,接口就没有意义
多态性好处:使用一个父类,就可以调用子类,如果子类很多,用多态就很方便
注:多态不适用属性,只适用于方法
注:
1.多态只能调用父类有的方法
2.如果想调用子类特有的方法,需要转换为子类对象
3.这时需要用到instanceof关键字
instanceof关键字
说明:多态不能调用子类特有的方法
如何才能调用子类特有的方法?
使用强制类型转换,向下转型 :Man man = (Man)person;
注:使用强转时,可能会出现类型转换异常,为了避免这个问题,需要使用 instanceof关键字
使用instanceof关键字:
格式:父类多态对象 instanceof 子类 (父类多态对象 是否是 子类的实例),是就向下转型
比如:if(person instanceof Man)
Man man = (Man)person;
man.特有方法();
十二、Object类 和 包装类
Object类
说明:java中所有类的根父类,没有继承关系的类,默认父类就是Object类
1.Object类中只声明了一个空参构造器
2.方法:
(1)notify()、notifyAll()、wait() 线程通信
(2)hashCode() 集合哈希值
(3)finalize():垃圾回收
(4)getClass():获取当前对象的所属类
(5)equals():比较两个对象是否相等,可以重写:比较对象实体
(6)toString():获取内存地址值,可以重写:返回实体内容
包装类
基本数据类型>引用数据类型:包装类
把基本数据类型封装,变成对象,就叫包装类
8种基本数据类型:除 int>Integer ,char>character ,其余6种,首字母大写
除char、boolean,其余6种父类都是Number
注:包装类是对象,不能进行加减乘除运算,且默认值都是 Null
基本数据、包装类 和 String 之间相互转换:
~~1.基本数据类型>包装类~~
~~包装类 i = new 包装类(变量);~~
~~2.包装类>基本数据类型~~
~~调用包装类的:类型Value()~~
3.基本数据类型、包装类 > Stirng
(1)Stirng str = 变量 + " ";
(2)String.ValueOf(包装类/基本数据类)
4.String >基本数据类型、包装类
包装类.parseXxx(str);
>Xxx:包装类的基本数据类型
jdk5.0新特性:自动装箱和拆箱
即不需要手动 基本数据类型和包装类转换了
自动装箱:基本>包装
int num = 10 ; Integer i = num;
自动拆箱:包装>基本
int b = i;
十三、static关键字 和 final关键字
static关键字
说明:
1.修饰:属性、方法、代码块、内部类
2.修饰属性:静态变量(类变量)
注:属性按是否被static修饰,分为静态变量、非静态变量(实例变量)
静态变量:共享变量,修改会影响其它对象的静态变量;
实例变量:每个对象都有自己的值,修改不影响其它对象
>静态变量随着类的加载而加载,可通过 “类.属性” 直接使用
>静态变量的加载早于对象的创建
>静态变量归类所有
>只加载一次,静态变量也只存在一份,存在于方法区静态域
3.修饰方法:静态方法
>随着类的加载而加载,可通过 “类.方法”直接使用
>静态方法中,只能调用静态方法、属性
非静态方法,都可以调用
>静态方法中,不可使用 this、super关键字
因为静态方法早于它们加载,调不动
开发中如何确定一个“属性”要不要使用 static关键字:
>属性共有,比如国家
>类中常量 也可以声明static
开发中如何确定一个“方法”要不要使用 static关键字:
>操作静态属性方法
>工具类中的方法
final关键字
说明:
1.修饰:变量、方法、类
2.修饰变量:常量
>修饰属性:可以考虑赋值位置:显式、代码块、构造器
>修饰局部变量:常量,不能被重新赋值
3.修饰方法:不能被重写
4.修饰类:不能被继承
static final:
>修饰属性:全局常量
>修饰方法:直接通过类调用,不能被重写(注:通常不用)
十四、代码块、内部类
代码块
格式:{ }
作用:初始化类、对象
说明:
1.内部可以有输出语句
1.代码块分为静态代码块、非静态代码块
(1)静态代码块 static{ }
>随着类的加载而加载执行,只加载执行一次
>作用:初始化类的信息
>定义多个静态代码块,先后顺序执行
>静态代码块执行,优先于非静态代码块
>静态代码块只能调用静态方法
(2)非静态代码块
>随着对象创建而加载执行
>每创建一个对象,就执行一次
>作用:初始化对象属性
注:代码块只能被 static 修饰
内部类
说明:
1.一个类定义在另一个类中,前者“内部类”,后者“内部类”
2.分类:
>成员内部类:静态、非静态
>局部内部类:方法、代码块、构造器内
成员内部类:
1.可以调用外部类结构,比如方法、属性等
2.可以用staic修饰,修饰后就是静态
3.可以被4种权限修饰符修饰
4.可以定义属性、方法、构造器
5、可以被final修饰,修饰后不能被继承
6.可以被abstract修饰,修饰后不能实例化
实例化成员内部类:
>静态成员内部类(可以直接被调用)
外部类.内部类 对象名 = new 外部类.内部类();
>非静态成员内部类:
1.先创建外部类对象
2.外部类.内部类 对象名 =外部类对象.new 内部类();
区分内部类调用外部类结构:
>区分同名属性
外部类属性:外部类.this.属性
内部类属性:this.属性
这里有点绕,自行体会
注:局部内部类开发中很少见
--------------------------------------------------------------
十五、abstract 和 接口 interface implements关键字
abstract关键字:
说明:
1.修饰:类、方法
2.修饰类:抽象类
>不能创造对象
>一定有构造器,便于子类实例化
>开发中,抽象类一定有子类
3.修饰方法:抽象方法
>没有方法体
>一定在抽象类中
>由子类重写其方法
注:
1.abstract 只能修饰类和方法
2.不能修饰 private私有,static静态、final 方法和类
抽象类的体现及应用:模版方法设计模式
抽象类作为多个子类的通用模版,子类可以扩展,并保留父类抽象类的属性行为
解决问题:
开发功能有一部分是固定,有一部分不确定
固定的交给父类抽象类,不确定的交给子类
接口 interface implements关键字
说明:
1.interface:代表接口
2.implements:代表 实现接口 ,实现接口的类被称为实现类
interface 使用:public interface 类名{} //类名即接口名
implements 使用: public class 类名 implements 接口名{}
注:
1.实现多个接口,且接口之间有相同方法,或者和父类有相同方法,会冲突,必须重写
2.接口不能有构造器,不可以实例化
3.实现类没有重写接口所有抽象方法,那么实现类依旧是抽象类
4.实现类可以实现多个接口
5.接口之间可以多继承
6.接口具体使用:必须体现多态性
如: UserDao userDao = new UserDaoImpl();
//UserDao是接口,UserDaoImpl是UserDao的实现类;
接口的体现及应用:代理模式
结构:接口、被代理实现类、代理实现类
代理实现类:
1.私有接口的对象
2.带参构造器
3.方法中调用对象的方法
4.main方法中,创建代理带参对象
代理分类:静态代理、动态代理
应用场景:安全代理、远程代理、延迟加载
main方法
说明:
1.一个程序的入口
2.也可以当做一个普通的静态方法
3.作为与控制台交互的方式(比如 Scanner 输入)
|