Java八股(关键字)
final 关键字
final关键字主要有以下三个方面的作用:用于修饰类、方法和变量。
final 修饰类
当final修饰一个类时,表示这个类不能被继承,是类继承体系中的最终形态。
final 修饰方法
用final修饰的方法不能被重写。
final 修饰变量
final 修饰基本数据类型变量
当final修饰基本数据类型的变量时,该变量一旦被赋值就不能再改变。例如,final int num = 10;,这里的num就是一个常量,不能再对其进行重新赋值操作,否则会导致编译错误。并且在创建时必须赋值。
final 修饰引用类型变量
当final修饰一个引用数据类型变量的时候,该变量在类初始化完成之前,必须完成赋值。
static 关键字
static 关键字主要用于修饰类的成员(变量、方法、代码块)和内部类,其核心作用是将成员与类本身关联,而非与类的实例(对象)关联。
用static修饰的成员和内部类都只和类本身有关,无论创建该类的多少个对象,该值都是同一个共享值。更具这一特性,可以用静态值来实现计数器等功能。
static 修饰方法
静态方法属于类,不属于任何实例,因此不能直接访问类中的非静态成员(变量 / 方法)(因为非静态成员依赖于对象存在),但可以访问静态成员。通过 类名.方法名 直接调用,无需创建对象。
通常用于工具类方法(如 Math.random())、工厂方法等,不需要依赖对象状态即可完成操作。
正是因为static修饰的成员都是直接服务类的,而不是对象,所以可以通过类名直接调用静态的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class MathUtils { public static int add(int a, int b) { return a + b; } }
public class Test { public static void main(String[] args) { int result = MathUtils.add(2, 3); } }
|
static 修饰变量
被 static 修饰的变量属于类本身,而非类的某个实例。所有对象共享同一份静态变量,内存中只存在一份副本。可以通过 类名.变量名 直接访问,无需创建对象。
通常用于存储所有对象共享的数据,如常量、计数器等。
也可以修饰引用对象。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Student { public static String schoolName = "阳光中学"; private String name; }
public class Test { public static void main(String[] args) { System.out.println(Student.schoolName); } }
|
static 修饰代码块
静态代码块在类加载时执行,且只执行一次(优于对象构造方法),用于初始化静态变量或执行类级别的预处理操作。
意味着,虽然静态修饰的final对象在定义的时候必须初始化,但是可以通过静态代码块来完成初始化过程,这样的操作在redis的 java 连接池创建中很常见。比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class jedisConnectionFactory { private static final JedisPool jedisPoll; static { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(8); jedisPoolConfig.setMaxIdle(8); jedisPoolConfig.setMinIdle(0); jedisPoolConfig.setMaxWait(Duration.ofMillis(200)); jedisPoll = new JedisPool(jedisPoolConfig, "123.207.22.15", 6379,1000,"Ljj20010315_"); } public static Jedis getJedis() { return jedisPoll.getResource(); } }
|
static 修饰内部类
用static修饰内部类后,内部类就变成了静态内部类,静态内部类不能调用外部类中的变量和方法。想要访问内部类,就必须要创建外部类的实例进行访问。
当内部类与外部类的实例无关时使用,避免内部类持有外部类的引用导致的内存泄漏。(外部类没用用上,但是不用static修饰就必须创建外部类,由此导致外部类中的变量、方法都还存在在内存中,最终导致内存泄露。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class OuterClass { private static int staticVar = 10; private int instanceVar = 20; public static class StaticInnerClass { public void print() { System.out.println(staticVar); } } }
public class Test { public static void main(String[] args) { OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass(); inner.print(); } }
|
深拷贝和浅拷贝
深拷贝和浅拷贝的区别
浅拷贝:浅拷贝是指只复制对象本身和其内部的值类型字段,但不会复制对象内部的引用类型字段。
深拷贝:深拷贝是指在复制对象的同时,将对象内部的所有引用类型字段的内容也复制一份,而不是共享引用。

实现深拷贝的三种方法
实现 Cloneable 接口并重写 clone() 方法
要求对象及其所有引用类型字段都实现 Cloneable 接口,并且重写 clone() 方法。在 clone() 方法中,通过递归克隆引用类型字段来实现深拷贝。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class MyClass implements Cloneable { private String field1; private NestedClass nestedObject;
@Override protected Object clone() throws CloneNotSupportedException { MyClass cloned = (MyClass) super.clone(); cloned.nestedObject = (NestedClass) nestedObject.clone(); return cloned; } }
class NestedClass implements Cloneable { private int nestedField;
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
|
使用对象的序列化和反序列化
通过将对象序列化为字节流,再从字节流反序列化为对象来实现深拷贝。要求对象及其所有引用类型字段都实现 Serializable 接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import java.io.*;
class MyClass implements Serializable { private String field1; private NestedClass nestedObject;
public MyClass deepCopy() { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); oos.flush(); oos.close();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (MyClass) ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); return null; } } }
class NestedClass implements Serializable { private int nestedField; }
|
手动的递归复制
针对特定对象结构,手动递归复制对象及其引用类型字段。适用于对象结构复杂度不高的情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class MyClass { private String field1; private NestedClass nestedObject;
public MyClass deepCopy() { MyClass copy = new MyClass(); copy.setField1(this.field1); copy.setNestedObject(this.nestedObject.deepCopy()); return copy; } }
class NestedClass { private int nestedField;
public NestedClass deepCopy() { NestedClass copy = new NestedClass(); copy.setNestedField(this.nestedField); return copy; } }
|
通过上面的三种方法我们可以发现,所谓深拷贝,就是想要拷贝的类的对象中包含了另外一个类的对象。
在深拷贝中,除了拷贝本身的类的成员,还要去考虑copy另外一个类的对象,但是在实际操作中,本质上都是在两个类中都去实现一个copy()方法,分别完成各个成员的拷贝,和对象的拷贝。
三种方法本质上都是去实现这个copy方法实现的。
Java八股(反射)