单例模式
模式:由专家总结出来的在某种情况下解决某类问题的最佳解决方案,是思想、是知识,是一种抽象的内容
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
单例模式有多种写法,最常见的是懒汉模式和饿汉模式
饿汉单例模式
优点:没有加锁,执行效率会提高
缺点:类加载时就初始化,浪费内存
编程实现:
私有构造器
静态的私有属性
公共的静态方法
懒汉单例模式
懒汉式:主要是针对饿汉式中不管是否需要使用对象都先创建对象所引起的内存浪费
优点:由于采用延迟处理的方式,所以比较节约内存
缺点:在多线程不能正常工作
静态
static
关键字
1.用于修饰成员
2.随着类加载,随着类消失
3.优先于对象,用类名直接访问
静态属性
static
属性是当前类的所有对象所共有的共同属性
(
只有一个,而普通属性各个对象都有自己的,相互隔离)
,任何一个当前类对象修改这个属性,所有其他类对象的这个属性都会受影响
典型应用:统计
A1
类的构建次数
执行顺序
静态属性
---
属性
---
构造器
访问的方式
可以使用
“
类名
.
静态属性名
”
或者
“
对象名
.
静态属性名
”
的方式进行访问。【范围限制】
定义常量
命名规则:名称全大写,下划线分词
声明语法:
public static final double MIN_NUMBER = 0.1;
声明的同时直接进行初始化
先声明后在
static
静态块中赋值
静态方法
因为可以直接使用
”
类名
.
方法名
”
的形式直接调用静态方法,静态方法执行时很有可能并没有构建对
象,所以在静态方法中不允许使用
this/super
之类用于指定对象的关键字
当然在静态方法中允许创建对象,并调用对象方法
静态方法只能直接访问静态成员,不能直接访问非静态成员
static
关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。
Java
中
static
方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而
static
方法是编译时静态绑定的。static
方法跟类的任何实例都不相关,所以概念上不适用
静态块
类在执行时需要通过一个叫作类加载器的组件将程序加载到内存中,类在运行时一般不会发生变
化,所以类不会频繁加载,在整个运行过程中只加载一次,而且常驻内存
静态块在类加载完毕后自动执行,而且只执行一次
非静态块
非静态块在类内且在所有的方法之外,非静态块并不会在类加载后自动执行,而是在构建当前对象时自动执行。new
一次则会执行一次,执行时机在构造器之前执行。
考试点
当类加载完毕会自动优先处理
static
属性和
static
块,这两个优先级是相同的,所以谁在前先处理谁
new
对象时,处理非静态属性和非静态块,这两个优先级是相同的,所以谁在前先处理谁,最后执行构造器
使用注意事项
静态方法只能访问静态成员,静态有访问局限性
静态方法中不能有
this super
关键字
主函数是静态的
什么时候使用静态
当成员变量的数据各个对象都相同时,可以用
static
修饰的,让多个对象共享
方法如果访问了特有数据(非静态成员变量),该函数是非静态的。方法如果没有访问特有数据,
那么该方法就是静态修饰
如果类中的功能都是静态的,那么该类创建对象是没有意义的,所以构造方法需要私有化
静态导入
在一个类中反复使用到某个类中的静态方法,如果使用静态导入则在当前类中不需要再写类名称
在
JDK5
当中提供了导入静态方法的
import
语句。
1.语法:
import
static
java.lang.Math.*; -
导入
Math
类中的所有静态方法
2.注意要求使用
JDK1.5+
版本,否则编译不通过
成员应用细节
在程序执行过程中使用
new
运算符创建的
java
对象,存储在堆内存中。对象内部有实例变量,所以实例变量存储在堆内存当中
变量分类:
局部变量,方法体中声明
成员变量,方法体外类内声明
1.实例变量,没有
static
修饰符,各个不同对象相互隔离
2.静态变量,有
static
修饰符,这个类的所有对象共享
3.静态变量存储在方法区内存中
三块主要内存中变化最频繁的是栈内存,最先有数据的是方法区内存,垃圾回收期主要针对的是堆
内存
自动垃圾回收机制
GC
什么时候会将
java
对象的内存回收
当堆内存中的对象称为垃圾数据的时候会被
GC
回收
什么时候堆内存对象会变成垃圾?
引用计数法:为每个对象创建一个引用计数器,有对象引用时计数器
+1
,引用被释放时计数
器
-1
,当计数器为
0
时就可以被回收。它有一个缺点就是不能解决循环引用的问题
可达性算法(引用链法):从
GC Roots
开始向下搜索,搜索所走过的路径称为引用链。当一
个对象到
GC Roots
没有任何引用链相连时,则证明此对象是可以被回收的。
总结
栈内存存储基本类型的变量和对象的引用变量
堆内存用于存放由
new
创建的对象和数组。每
new
一个对象就在堆内存中开辟一个新的存储空间存
储此实例对象
Person p = new Person()
执行
new
命令时程序执行两步:
a:
在堆内存中开辟一段空间,存储
new
出
来的对象;
b:
在栈内存中添加一个变量
p
,
p
中存放的是该对象在堆内存中开始存放处的物理地址
p = null;
执行此步骤的时候程序只是更改栈内存中的
P
变量所保存的地址,把地址指向
null,
而并没
有操作堆内存(把
p
所指向的对象实例清空回收)
无论是形参或者实参,执行
XXX = null;
操作时都是把
XXX
变量栈中存储的地址改为指向
null
的地
址。不操作堆中的数据。
具体问题
由类创建一个对象,
JVM
内存中发生了哪些事情?
MyClass mc = new MyClass();
以这条语句为例,
MyClass mc =
使虚拟机栈中生成了一个指向
MyClass
对象的地址;
new MyClass()
则在堆中分配了对象
mc
成员变量的空间。
栈和堆的区别
管理方式:栈自动释放,堆需要
GC
空间大小:栈比堆小
碎片相关:栈产生的碎片远小于堆
分配方式:栈支持静态和动态分配,而堆仅仅支持动态分配
效率:栈的效率比堆高
方法的问题
方法的分类:
1.无参无返(没有参数列表,没有返回值)单纯的作为 功能代码的聚合使用 便于功能复用
2.无参有返(没有参数列表,有返回值)
3.有参无返(有参数列表 没有返回值)适用于功能需要根据参数来进行计算的情况,但是计算的最终结果又无需返回处理
4.有参有返(有参数列表,有返回值)适用于功能需要根据参数来进行计算的情况,而且最终的结果
需要返回处理
方法的形参和实参:
形参 :是定义在方法声明上,用于指定该方法需要传递的参数类型的
实参 :是调用方法时,实际传递的参数值
方法参数传递
基本数据类型作为参数传值:传值传的时值的内容,来到另一个方法空间之后,这个值和之前没有
任何关系。(如你们拷贝我分享的网盘内容不会改变我原有玩盘内容)
引用数据类型作为参数传值:传值传的时对象在堆的地址值,所以了两个内容指向了同一空间是相
互影响的。(如你登陆我的网盘拷贝内容改变的话会改变我的网盘内容)
基本数据类型的对象缓存
在不可变类
Integer
类定义中查看源代码可以发现一个定义
是因为在
Integer
中包含有一个缓存池,缓存值为
-128
到
127
之间。
定义
Integer k1=12
是先在缓存池中查找
12
这个对象,如果有则直接使用
new Integer(12)
一定会引发对象的创建,而不管缓存池中是否包含这个对象
Integer\Long\Short\Byte
中都有缓存池、
character
中也有缓存池,
boolean
只有
true/false
两个
字符串缓存池
String
中包含一个缓存池,当使用某个字符串对象时会首先在缓存池中进行查找,如果存在则直接返回这个对象的地址;如果不存在则会在缓存池中进行创建,创建完成后返回地址
注意:如果通过字串拼接所得内容和某个字串内容一致,但是地址不同
装箱
/
拆箱
值类型自动转换成它对应的类类型
-autoboxing
、类类型自动转成它所对应的值类型
-unboxing
装箱。如:
Integer a = 9;
将一个对像自动转成基本类型就叫拆箱
int c = new Integer(9);
java.lang.Object
所有
Java
类都直接或者间接的继承自
Object
类,那么
Object
中的方法也是其他所有类都拥有的
Object
类中的常用方法
getClass
方法用于获得当前对象的类型
直接输出一个对象时,实际上默认输出的是该对象
toString()
方法的返回值。所有的
Java
类中都有这个方法,因为Java
类都直接或者间接的继承于
Object
类,而
Object
类中定义了
toString
方法。为了实现用户自定义输出格式,允许在类中覆盖定义toString
方法
Java
中的约定:重写
equals()
方法必须重写
hasCode()
方法
hashCode()
方法返回一个整形数值,表示该对象的哈希码值。
hashCode()
具有如下约定:
1).
在
Java
应用程序程序执行期间,对于同一对象多次调用
hashCode()
方法时,其返回的哈希码是相同的,前提是将对象进行equals
比较时所用的标尺信息未做修改。在
Java
应用程序的一次执行到另外一次执行,同一对象的hashCode()
返回的哈希码无须保持一致;
2).
如果两个对象相等(依据:调用
equals()
方法),那么这两个对象调用
hashCode()
返回的哈希码也必须相等;
3).
反之,两个对象调用
hasCode()
返回的哈希码相等,这两个对象不一定相等。
多态性
多态性是发送消息给某个对象,让该对象自行决定响应何种行为。通过将子类对象引用赋值给超类对象
引用变量来实现动态方法调用
多态性通过允许同一界面指定一类动作减少了程序的复杂度,编译器工作就是选择适用于各个情况的特定动作,而程序员则无须手动进行选择,使用者仅仅是记得以及利用这个统一的界面
多态形成的三个必要条件:
1.有继承,父类定义方法,子类重写方法
2.父类的引用指向子类的对象
3.可以使用参数传递时多态,也可以直接创建对象时多态
多态可以用
三个定义和两个方法
来总结。三个定义分别是父类定义子类构建、接口定义实现类构建和抽象类定义实体类构建,而两个方法分别是方法重载和方法重写。
多态分为两种:
1.编译时多态:方法的重载
2.运行时多态:
JAVA
运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态