java要多多练习!:
JVM 内存即 Java 虚拟机内存,是 Java 程序运行时用于存储数据的区域 。Java 程序在运行时,JVM 会在计算机物理内存上划分出不同的内存区域来管理数据,主要分为以下几部分:
new
关键字创建的对象)和数组,几乎所有对象实例都在此分配内存。类加载器读取类文件后,类的元数据(如类、方法和常量等信息 )也会存放在堆内存。MaxPermSize
限制,而是由系统实际可用空间决定,这使得类元数据的存储更灵活。此外,还有程序计数器(记录当前线程执行程序的位置 ,是线程私有内存区域 )和直接内存(不是 JVM 规范定义的内存区域,NIO 可调用 Native 方法直接分配堆外内存,即本机内存 ,不影响堆内存大小 ) 。合理管理和配置 JVM 内存,对 Java 程序的性能和稳定性至关重要 。
ThreadLocal
是 Java 中位于 java.lang
包下的一个类 ,用于提供线程局部变量。以下是其相关介绍:
为每个使用该变量的线程提供独立的变量副本,各线程可独立修改自己的副本,不影响其他线程副本。在多线程环境下,能避免线程安全问题,简化多线程编程。比如在多线程 Web 应用里,可给每个线程创建独立数据库连接,防止多个线程共享连接引发并发问题 ;也可用于事务管理,存储每个线程的事务状态等信息。
ThreadLocalMap
(ThreadLocal
类的内部静态类 )。当线程调用 ThreadLocal
的 set(T value)
方法设置变量时,以 ThreadLocal
实例为键、变量值为值,存于该线程的 ThreadLocalMap
中;调用 get()
方法时,从自身的 ThreadLocalMap
中取值。ThreadLocalMap
中 Entry
继承自 WeakReference>
,即 Entry
的键(ThreadLocal
实例 )是弱引用。若 ThreadLocal
实例无强引用指向,垃圾回收时会被回收,但 Entry
中的值不会,可能导致内存泄漏。所以使用完要及时调用 remove()
方法清理。T get()
:返回当前线程中该 ThreadLocal
变量副本的值。若当前线程无对应值,先调用 initialValue()
方法初始化并返回。void set(T value)
:将当前线程中该 ThreadLocal
变量副本的值设为指定值 。void remove()
:移除当前线程中该 ThreadLocal
变量副本的值。后续该线程读取时,若未重新设置值,会重新调用 initialValue()
方法初始化。protected T initialValue()
:返回当前线程中该 ThreadLocal
变量的初始值。线程首次调用 get()
方法(且之前未调用 set(T value)
方法 )时执行,默认返回 null
,可被子类重写以指定初始值。还可通过静态方法 withInitial(Supplier extends S> supplier)
创建 ThreadLocal
变量并指定初始值。ThreadLocal
使用不当可能引发内存泄漏,及时调用 remove()
方法很重要。也可将 ThreadLocal
设为全局变量(如 public static
修饰 ),避免被回收从而防止内存泄漏。ThreadLocal
时若前一个任务设置的值未清理,后续任务可能使用到脏数据。所以在线程池场景,任务开始时初始化 ThreadLocal
,结束时调用 remove()
方法清理。 此外,InheritableThreadLocal
是 ThreadLocal
的子类,可实现子线程继承父线程的 ThreadLocal
变量副本;还有阿里开源的 TransmittableThreadLocal
,可解决线程池等场景下 InheritableThreadLocal
传递值不符合预期的问题。在Java中,final变量(成员变量)必须在以下位置之一进行初始化:
1. 声明时直接初始化
2. 在构造方法中初始化
3. 在初始化块中初始化
如果没有初始化会造成编译错误。非final的成员变量j会被自动初始化为0。
在 Java 里,Object
类是所有类的根类,这意味着每个类都会继承 Object
类的方法。下面是 Object
类的一些基本方法:
toString()
方法此方法会返回对象的字符串表示。默认情况下,它返回的是类名加上 @
符号以及对象的哈希码。通常会重写这个方法,从而返回更具意义的字符串。
class MyClass {
private int value;
public MyClass(int value) {
this.value = value;
}
@Override
public String toString() {
return "MyClass{value=" + value + "}";
}
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass(42);
System.out.println(obj.toString());
}
}
equals()
方法该方法用于比较两个对象是否相等。默认情况下,它比较的是对象的引用,也就是判断两个对象是否为同一个实例。不过,许多类都会重写这个方法,以便根据对象的内容进行比较。
class MyClass {
private int value;
public MyClass(int value) {
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyClass myClass = (MyClass) o;
return value == myClass.value;
}
}
public class Main {
public static void main(String[] args) {
MyClass obj1 = new MyClass(42);
MyClass obj2 = new MyClass(42);
System.out.println(obj1.equals(obj2));
}
}
hashCode()
方法此方法返回对象的哈希码值。在将对象存储到哈希表(像 HashMap
或 HashSet
)时,这个方法会被使用。当重写 equals()
方法时,通常也需要重写 hashCode()
方法,以保证相等的对象具有相同的哈希码。
import java.util.Objects;
class MyClass {
private int value;
public MyClass(int value) {
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyClass myClass = (MyClass) o;
return value == myClass.value;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass(42);
System.out.println(obj.hashCode());
}
}
getClass()
方法该方法返回对象的运行时类。它返回的是一个 Class
对象,这个对象包含了类的各种信息。
class MyClass {}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
Class> clazz = obj.getClass();
System.out.println(clazz.getName());
}
}
clone()
方法此方法用于创建并返回对象的一个副本。不过,要使用这个方法,类必须实现 Cloneable
接口,否则会抛出 CloneNotSupportedException
异常。
class MyClass implements Cloneable {
private int value;
public MyClass(int value) {
this.value = value;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) {
try {
MyClass obj1 = new MyClass(42);
MyClass obj2 = (MyClass) obj1.clone();
System.out.println(obj2.value);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
finalize()
方法这个方法在对象被垃圾回收之前会被调用。不过,不建议依赖这个方法来进行资源清理,因为它的调用时间是不确定的,而且从 Java 9 开始,该方法已被弃用。
class MyClass {
@Override
protected void finalize() throws Throwable {
System.out.println("Object is being garbage collected");
super.finalize();
}
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj = null;
System.gc();
}
}
notify()
, notifyAll()
和 wait()
方法这些方法用于线程间的通信。notify()
会唤醒在此对象监视器上等待的单个线程,notifyAll()
会唤醒在此对象监视器上等待的所有线程,而 wait()
会让当前线程等待,直到其他线程调用该对象的 notify()
或 notifyAll()
方法。
class SharedResource {
private boolean flag = false;
public synchronized void waitForFlag() throws InterruptedException {
while (!flag) {
wait();
}
System.out.println("Flag is set, continuing...");
}
public synchronized void setFlag() {
flag = true;
notifyAll();
}
}
public class Main {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread t1 = new Thread(() -> {
try {
resource.waitForFlag();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.setFlag();
});
t1.start();
t2.start();
}
}
这些就是 Object
类的基本方法,在 Java 编程中经常会用到。
在 Java 里,哈希码(Hash Code)是一个由对象的 hashCode()
方法返回的整数值。下面从基本概念、生成方式、使用规则、作用、潜在问题几个方面详细介绍 Java 中的哈希码。
Java 中每个对象都继承自 Object
类,而 Object
类有一个 hashCode()
方法,其用途是为对象生成一个唯一标识整数。默认情况下,这个整数基于对象在内存中的地址生成。不过,很多类会重写 hashCode()
方法,以便根据对象的内容来生成哈希码。
hashCode()
方法,那么对象的哈希码就由 Object
类的 hashCode()
方法生成,通常和对象的内存地址有关。class DefaultHashCodeExample {
public static void main(String[] args) {
Object obj = new Object();
System.out.println(obj.hashCode());
}
}
hashCode()
方法。一般会结合对象的属性来计算哈希码。import java.util.Objects;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
在 Java 里使用哈希码时,要遵循下面的规则:
equals()
方法的比较信息没有改变,那么多次调用 hashCode()
方法必须返回相同的整数。equals()
方法比较是相等的,那么它们调用 hashCode()
方法必须返回相同的整数结果。equals()
方法比较是不相等的,那么调用 hashCode()
方法不一定要求返回不同的整数。不过,为不同对象生成不同的哈希码可以提高哈希表的性能。HashMap
、HashSet
等)里起着关键作用。哈希表借助哈希码来确定元素在内部数组中的存储位置,以此实现快速的插入、查找和删除操作。import java.util.HashMap;
import java.util.Map;
public class HashCodeInHashMap {
public static void main(String[] args) {
Map personMap = new HashMap<>();
Person person = new Person("Alice", 25);
personMap.put(person, "Some value");
String value = personMap.get(person);
System.out.println(value);
}
}
hashCode()
方法时,要尽量保证计算过程高效。