JAVA面向对象核心部分
1 类变量static
类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。这个从前面的图也可看出来。
package day111;
/**
* @ClassName staticClass
* @Description
* @Date 2024/11/26 9:13
* @Version V1.0
*/
public class staticClass {
public static void main(String[] args) {
int count = 0;
Child child1 = new Child("白骨精");
child1.join();
child1.count++;
Child child2 = new Child("狐狸精");
child2.join();
child2.count++;
Child child3 = new Child("老鼠精");
child3.join();
child3.count++;
System.out.println("共有" + Child.count + " 小孩加入了游戏...");
System.out.println("child1.count=" + child1.count);//3
System.out.println("child2.count=" + child2.count);//3
System.out.println("child3.count=" + child3.count);//3
}
}
class Child { //类
//定义一个变量 count ,是一个类变量(静态变量) static 静态
//该变量最大的特点就是会被 Child 类的所有的对象实例共享
public static int count = 0;
private String name;
public Child(String name) {
this.name = name;
}
public void join() {
System.out.println(name + " 加入了游戏..");
}
}
1.什么时候需要用类变量:当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量);比如:定义学生类,统计所有学生共交多少钱。
Student(name,static fee)2.类变量与实例变量(普通属性)区别类变量是该类的所有对象共享的,而实例变量是每个对象独享的。
3.加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量。4.类变量可以通过 [类名.类变量名] 或者 [对象名.类变量名]来访问,但iava设计者推荐我们使用类名.类变量名方式访问。【前提是满足访问修饰符的访问权限和范围】
5.类变量在类加载时就初始化了,类加载了就可以使用类变量。生命周期与类相关。
1.1 static方法
当方法中不涉及对象成员的时候,建议将方法写成static,如utils类。开源的Math、Arrays、Collection类源码如下:
技巧:通用方法开发为静态,方便使用。
注意:
- 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:类方法中无this的参数
- 类方法可以通过类名调用,也可以通过对象名调用。
- 普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用。
- 类方法中不允许使用对象的关键字this和super
- 类方法(静态方法)中只能访问静态方法和静态变量。
1.2 main方法
在 main()方法中, 我们可以直接调用 main 方法所在类的静态方法或静态属性。但是, 不能直接访问该类中的非静态成员, 必须创建该类的一个实例对象后, 才能通过这个对象去访问类中的非静态成员。
2 初始化块
Static Initialization Block:
属于类中的成员[即 是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。
但和方法不同,没有方法名没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时或创建对象时隐式调用。
public class Demo {
private static String msg = "hello";
static {
// 初始化
msg = "world";
System.out.println("静态初始化块");
}
public static void main(String[] args) {
System.out.println(msg);
}
}
Instance Initialization Block:
public class Demo {
private String msg = "";
{
// 初始化
msg = "B";
}
}
3 单例模式
涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。
这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
优点:内存中只有一个实例,减少内存开销,尤其是频繁创建和销毁实例时(如管理学院首页页面缓存)。避免资源的多重占用(如写文件操作)。
缺点:没有接口,不能继承。与单一职责原则冲突。
3.1 懒汉式
//最基本的方式,但是线程不安全(没有加锁)。
public class Singleton {
private static Singleton instance;
private Singleton (){} //构造器私有化
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//加锁
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
3.2 饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。容易产生垃圾对象
3.3 Double-Checkd locking
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
采用双锁机制,安全且在多线程情况下能保持高性能。
3.4 登记式/static类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
3.5 枚举
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
更简洁,自动支持序列化机制
4 final关键字
final是一个关键字,可以用于修饰类,成员变量,成员方法。
特点:
- 它修饰的类不能被继承。
- 它修饰的成员变量是一个常量。
- 它修饰的成员方法是不能被子类重写的。
final修饰的常量定义一般都有书写规范,被final修饰的常量名称,所有字母都大写。public final double TAX_RATE=0.08;
final修饰成员变量,必须初始化,初始化有两种
- 显示初始化;
- 构造方法初始化。
但是不能两个一起初始化
final和private的区别:
- final修饰的类可以访问;
private不可以修饰外部类,但可以修饰内部类(其实把外部类私有化是没有意义的)。 - final修饰的方法不可以被子类重写;
private修饰的方法表面上看是可以被子类重写的,其实不可以,子类是看不到父类的私有方法的。 - final修饰的变量只能在显示初始化或者构造函数初始化的时候赋值一次,以后不允许更改;
private修饰的变量,也不允许直接被子类或一个包中的其它类访问或修改,但是他可以通过set和get方法对其改值和取值。