Java面对对象第七天(实训学习整理资料(六)Java中的面向对象(oop))
目录
1、定义
2、类与对象的关系
3、类中的构造方法
(1)特点
(2)作用
4、对象中的内存结构
5、this关键字
6、代码块
(1)构造代码块
(2)局部代码块
(3)静态代码块
7、匿名对象
8、类加载机制(classLoader)
9、成员变量和局部变量
10、面向对象的三大特性
(1)封装性
(2)继承性
1--定义
2--构建方式
3--继承的应用场景
4--分析继承的使用
(3)多态性
1--定义
2--分类
11.方法重写
12、super关键字
13、其他知识
(1)静态(static)
(2)final
(3)抽象(abstract)
(4)接口(interface)
(5)内部类
1--方法内部类(局部内部类)
2--成员内部类
3--静态内部类
4--匿名内部类
5--接口内部类
6--内部接口
14、package包
15、垃圾分代回收机制
(1)定义
(2)如何判定垃圾对象
(3)如何启动垃圾回收器
(4)jvm运行时内存区域
(5)堆内存区域(垃圾回收区域)
1、定义
面向对象和面向过程都是一种编程思想。java是一种纯面向对象的语言(一切皆为对象)。
2、类与对象的关系
类是创建对象的模板,对象是类的一个具体实例。
在Java开发过程中,对对象进行抽象(类的封装)。
每个对象身上都有相应的成员属性和成员方法。
用“有”描述的,就是对象的特征 --属性
用“能做什么”描述的,就是对象的功能 --方法
Java中如何实例化对象?使用new关键字实例化对象。
类型 对象名 = new 类型();
3、类中的构造方法
(1)特点
构造方法是类中的一个特殊方法,该方法没有返回值(不需要设置返回值类型)。并且方法名与类名相同。
(2)作用
在实例化对象时,自动调用的第一个方法。
注意:
类中如果没有构造方法,则jvm在加载类时,会自动创建一个无参构造。
如果已经定义了构造,则jvm就不会再创建。
一个类中是否允许出现多个构造方法?--允许(方法重载)
4、对象中的内存结构
当对象被构建时,对象中的所有属性都会被初始化。
byte/short/int->0, long -> 0L, float -> 0.0f, double -> 0.0d, boolean ->false char -> ‘\u0000’
5、this关键字
this表示当前类活动的对象。
用法一:在类的方法或属性中用于调用当前类的其他成员(属性,方法)
this.属性名; this.方法名称(参数);
用法二:this语句 ----- this()
this语句可以在构造方法中用于调用其他构造,并且只能出现在构造方法的第一行
6、代码块
(1)构造代码块
在实例化对象时自动调用的代码块,它出现在类中,方法外。
class类{
···{
//构造代码块
}
···
}
构造代码块可以用在类的成员属性初始化。构造代码块优先于构造方法执行。
(2)局部代码块
在方法内定义的代码块,就是局部代码块。它可以及时回收不再使用的内存空间。
(3)静态代码块
在类中,方法之外定义的静态代码块,代码块被static进行修饰。
可以用于对静态成员进行初始化。而且它只会在类第一次被使用时,调用一次。
static{
···
}
7、匿名对象
没有引用的对象,在整个运行过程中只会被创建一次,当执行完成后会被当成垃圾对象,等待Java的垃圾回收器进行回收,可以作为参数进行传递。
new类();
8、类加载机制(classLoader)
(1)加载:查找并导入class文件
(2)连接:把class的二进制加载到java运行环境(jvm)
--校验:验证class的结构完整及正确性
--准备:给静态变量分配存储空间
--解析:将符号引用转为直接引用
(3)初始化:对类的静态变量,静态代码块进行初始化操作
(4)使用
(5)卸载
9、成员变量和局部变量
(1)位置:
成员变量也叫属性,定义在类中,方法之外。
局部变量定义在代码块中。
(2)内存位置:
成员变量在堆内存中,伴随着对象。
局部变量,在栈中调用时分配。
(3)生命周期:
成员变量的生命周期其实就是对象的生命周期,对象被创建时进行初始化,对象被回收时,成员变量被销毁。
局部变量,实在代码块执行结束后释放空间。
(4)作用范围:
成员变量可以在类的任何地方被调用,在类当中,类似于全局。
局部变量的作用范围只在当前代码块中。
10、面向对象的三大特性
(1)封装性
目的是通过一些封装关键字实现对类成员的保护(数据--特征--属性)。
封装关键字:可以控制成员的可见范围
关键字 | 当前类 | 同胞类 | 非同胞类(子类) | 类外 |
private(私有) | 可用 | 不可用 | 不可用 | 不可用 |
protected(受保护) | 可用 | 可用 | 可用(非同胞子类) | 不可用 |
default(默认) | 可用 | 可用 | 不可用 | 不可用 |
public(公共) | 可用 | 可用 | 可用 | 可用 |
注意:在类中定义默认权限的成员,不写关键字就表示默认。
应用场景:
(1)属性:
在开发中如果没有特殊需求,应该将所有成员属性全部(private)私有化。
(2)方法:
在类中,如果是一个对外发布的功能方法,则该方法应该设置为public(共有)。
如果方法是当前类中其他方法的辅助方法,则该方法应该设置为private(私有)。
注意:权限修饰符是对类的成员属性和成员方法修饰的,不能使用在局部作用域下,包括非成员类。
(2)继承性
1--定义
如果一个类的部分属性和功能是可以复用的,则可以创建一个子类去继承它。
继承性是可扩展性的体现。
2--构建方式
classA{
···
}
//继承
class B extends A{
···
}
在以上代码中,B类就是A类的子类或者叫派生类;相反,A类是B类的父类或者叫基类。
注意:对于类而言,Java只支持单继承。
不支持多继承其原因是为了牺牲一部分灵活性从而来保证避免出现调用混乱问题,也称“菱形问题”。
3--继承的应用场景
1、实现对类的扩展(代码复用)
2、多态的基础(向上造型)
4--分析继承的使用
在类和类之间是否适用于继承,分析是否能够用"A是B"进行描述,如不行,最好是放弃。
(3)多态性
1--定义
同一种类型的不同对象在调用相同的指令时,返回不同的结果。
2--分类
编译时多态:
方法的重载构成了编译时多态。
运行时多态:
构建的对象可以直接赋值给它的父类型或接口类型,这种表现形式也称为向上造型。
注意:当使用向上造型来创建对象的时候,这个对象能干什么看父类中定义了什么;这个对象需要怎么完成,看的是子类中怎么写的。------父类就好像是一个目录,告诉你这里面有什么;子类就好像是正文,去解释这个目录。
11.方法重写
如果要在子类中重写父类的方法,则必须满足如下的原则:“两等两小一大”原则。
(1)两等:
1、子类的方法签名(方法名称与参数列表)与父类相同。
2、如果父类方法的返回值类型是基础类型,子类的方法返回值类型必须与父类的相同。
(2)两小:
1、如果父类方法的返回值类型是引用类型,子类方法的返回值类型必须为父类方法返回的类型或子类型。
2、如果父类方法抛出异常,则子类方法抛出的异常范围不能超过父类。
(3)一大:
1、除了私有(private)以外,子类方法的权限修饰符范围应该大于等于父类方法的范围。
12、super关键字
用法一:
可以在子类的方法中或者属性上访问父类中的成员,super.属性/方法()。
甚至在子类的方法中也可以调用父类被覆盖的方法。
用法二:super()语句
作用与this语句类似,只能在子类的构造方法中,调用父类的构造方法。
只能出现在构造方法的第一行。如果在子类的构造中没有添加super语句,jvm会自动在第一行添加一个无参构造的调用。
补充:继承中的问题
在继承的基础上,如果实例化子类对象,在内存中,会构建几个对象?
在实例化子类对象时,父类对象也会被创建,但是是被包含在子类对象中。对外,内存中仍然只有一个对象。
13、其他知识
(1)静态(static)
被static修饰的成员(属性,方法),称为静态成员也叫类成员。他们是在类加载时完成初始化。而且静态成员可以在没有创建对象时直接通过类就可以访问。
类成员也属于所有对象共享的成员。
静态变量:
在普通成员方法中可以定义静态变量吗? ---不行
在构造方法中可以定义吗? ---不行
静态方法:
直接通过类名就可以调用: 类.静态方法()
静态方法中也不能定义静态变量。
静态方法中不能使用非静态成员。
静态方法可以重载吗? ---可以重载 ---重载与方法签名相关
静态方法可以被继承吗? ---可以
静态方法可以被重写吗? ---不可以
如果子类中要定义与父类静态方法相同的方法,要么都为静态,要么都为非静态。
加载顺序:
父类静态--》子类静态--》父类非静态--》子类非静态
应用场景:
1--static只能用于修饰成员
2--static一般还用于设置常量
3--工具类中方法通常都是静态方法
(2)final
final一般表示最终的,一旦被定义就不能修改。
1--在方法中使用final
变量前使用final修饰,如果变量是基础类型,则值不能修改;如果是引用类型,则引用地址不能被修改。
2--用于修饰类
表示类不能被继承,该类也称为最终类。
3--设置常量
static final 使用在成员属性上,也表示常量。与上面的用法相同但是命名使用大写字母加下划线。
例如:图形类案例中圆周率是固定不变
private static final double PI = 3.14;
4--设置方法(最终方法)
方法被final修饰后,该方法不能被重写。
(3)抽象(abstract)
被abstract修饰的类称为抽象类,被abstract修饰的方法称为抽象方法。
如果在类中只要有一个方法是抽象方法,这个类一定是个抽象类。
抽象类中不一定会存在抽象方法。
抽象类是不能直接实例化的,必须把抽象类中的所有方法全部实现(重写),继承是前提。
抽象类中可以定义构造方法吗? ---可以
(4)接口(interface)
如果一个抽象类中,所有方法都是抽象方法时,应该将该类定义为接口。
如果要使用接口,就需要用一个类实现(implements)接口,并实现里面所有抽象方法。
java类中对于接口是支持多实现。
在接口中允许定义常量。
在接口中只能有抽象方法吗? --不是,从jdk1.8开始支持如下的两种方法
1、静态方法
2、默认方法(被default修饰的方法)
(5)内部类
在类/接口/方法中定义的类就是内部类
1--方法内部类(局部内部类)
在方法中定义的类。
方法内部类中可以访问外部类的所有成员,所在方法中的局部变量也可以访问,但是在方法内部类中不能定义静态成员。
2--成员内部类
定义在类中,方法外。
除了定义的位置与方法内部类不同而外,其他都一样。
//访问成员内部类的方法
new 外部类().new 内部类().方法名;
3--静态内部类
成员内部类被static修饰。静态内部类中可以定义任意的成员。但是外部的非静态成员不能访问。
//访问静态内部类的方法
new外部类().内部类().方法名();
4--匿名内部类
没有名字的内部类。通常伴随接口或抽象类出现。
new 接口/抽象类(){
//抽象方法的具体实现
}
匿名内部类中不能定义静态成员,能访问所在方法中的变量,但是不能访问外层类的非静态成员。
案例:
interface Day7Inter{
void prints();
void getInfo();
}
//使用匿名内部类实现接口的抽象方法。
Day7Inter day7Inter = new Day7Inter() {
public void prints(){
}
public void getInfo(){
}
};
5--接口内部类
在接口中定义的类,默认就是public static。
6--内部接口
类/接口中定义接口--内部接口--默认是静态的
在Java中,类的内部可以定义类也可以定义接口;接口中也能定义接口和类。
14、package包
1、package在其他语言中也叫命名空间(namespace),目的为了解决命名冲突。
2、package命名规范要求,多个层级的包中间使用.分隔,并且使用小写字母。
3、通常包的定义顺序是按照当前公司注册的域名倒写形式。
4、如果在java文件中需要引入第三方的类完成操作,则需要通过import关键字导包。 但java中有个特殊的包 java.lang无需导入。
5、导包形式:
a、导入具体包,只需安装包的路径导入
b、如果需要对当前包下的直接类导入,则可以使用代表通配符
c、如果一个类中所有的方法为静态方法,则可以使用静态导包,省略类名。 import static 工具类路径
6、java中常见包说明:
java.util---工具包---提供了一系列操作对象的类和方法,作为工具来使用
java.applet---小应用程序包---内嵌到浏览器
java.awt---图形界面+swing
java.io---数据传输
java.math---和数字以及数学运算有关的包
java.net---网络通信
java.nio---高并发(非阻塞式io)
java.security---数据安全
java.sql---和数据库进行交互
java.text---格式化
javax---是Java包的扩展包
org---第三方厂商提供的一些常用包
15、垃圾分代回收机制
(1)定义
垃圾分代回收机制是整合了多种垃圾回收算法共同实现的。垃圾回收是针对jvm运行时内存中堆内存。
(2)如何判定垃圾对象
如果一个对象在程序中不再被引用,则该对象就是等待回收的垃圾对象。对象的引用都是通过引用计数器完成的,引用计数为0表示没有引用。
以及通过GC Roots判定对象是否可达。
(3)如何启动垃圾回收器
Java中的垃圾回收,是由独立的一个垃圾回收线程进行监控和清理,程序员不需要管理。不过在Java的System类中提供了一个gc()方法,可以通知垃圾回收器进行清理,但不一定有用。
(4)jvm运行时内存区域
栈内存:方法调用开辟栈空间。
堆内存:对象都被保存在堆内存中,所以也是垃圾回收关注的内存区,是所有内存中最大的区域。
方法区:保存类的接口信息,静态常量池。
本地方法栈:主要用于处理Java中的本地方法 native,本地方法是其他语言实现的。
寄存器:用于记录每个线程执行到的指令位置,是所有内存区中永远不会出现内存溢出的区域。
从jdk1.7开始,已经慢慢引入元空间的概念,主要是将原来的方法区中的一部分放到堆,另一部分放到本地内存。
(5)堆内存区域(垃圾回收区域)
堆区:
新生代:
伊甸园区
幸存区:
幸存区0
幸存区1
伊甸园区与幸存区的内存比例:8:1:1
特点:内存大,对象存活率比较低。
适用于 复制算法,算法回收销量高。
复制算法必须要多余的空进行交换,所以内存使用率会下降。(空间换时间)
老年代:
垃圾回收频率比新生代更低,原因是里面存放的对象都是比较稳定的,如果不小心把老年代中的对象全部清理,可能会导致jvm运行出错。
在老年代中可以使用如下的算法:
(1)标记清除:
会产生大量的内存碎片。
内存分配效率低。
(2)标记整理:
不会产生内存碎片。
在内存空间整理会消耗一定的效率。
注意:如果一个对象比较大,在新生代中无法存储,则该对象会直接保存到老年代,如果老年代也无法保存,则抛出内存溢出错误。