Java是值传递。这意味着当将一个变量传给一个方法的时候,我们实际上是传递的是这个变量的的副本。
但是对于对象来说,我们传递的是其的副本,我们不可以改变对象的引用本身,但是我们可以调用其方法和修改其字段
class Person {
String name;
Person(String name) {
this.name = name;
}
}
void changeName(Person person, String newName) {
person.name = newName;
}
Person john = new Person("John");
changeName(john, "Jack");
System.out.println(john.name); // 输出 "Jack"
void changeName(Person person, String newName) {
person = new Person(newName);
}
Person john = new Person("John");
changeName(john, "Jack");
System.out.println(john.name); // 输出 "John"
在Java中,反射一种特性,它允许运行中的Java代码对自身进行检查,并对类,字段,方法进行操作。以下是反射的常见使用场景:
反射的实现主要涉及以下几个步骤:
获取Class对象:首先我们需要获取操作类的对象,通过.getClass()方法,或者通过类名直接获取
MyClass myObject = new MyClass();
Class<?> clazz1 = myObject.getClass();
System.out.println(clazz1.getName()); // 输出 "com.example.MyClass"
Class<?> clazz2 = Class.forName("com.example.MyClass");
System.out.println(clazz2.getName()); // 输出 "com.example.MyClass"
获取和操作成员:我们获得Class对象之后,就可以操作它的成员
Field field = clazz.getField("myField");
Object obj = clazz.newInstance();
field.set(obj, "New Value");
这段代码是使用Java反射API来操作类的字段。让我逐行解释一下:
Field field = clazz.getField("myField");
:这行代码是获取名为myField
的字段的Field
对象。clazz
是我们想要操作的类的Class
对象。
Object obj = clazz.newInstance();
:这行代码是创建一个clazz
类的新实例。newInstance()
方法会调用类的无参数构造器来创建新的对象。
field.set(obj, "New Value");
:这行代码是将obj
对象的myField
字段设置为"New Value"
。set()
方法需要两个参数:第一个参数是我们想要操作的对象,第二个参数是我们想要设置的新值。
所以,总的来说,这段代码的作用是创建了一个clazz
类的新实例,并将其myField
字段设置为"New Value"
。
创建和操作对象:我们还可以使用Class对象来创建新的对象实例,或者调用对象的方法:
public class Person {
public String name;
public Person(String name) {
this.name = name;
}
public void sayHello(String greeting) {
System.out.println(greeting + ", " + name + "!");
}
public static void main(String[] args) throws Exception {
// 获取Person类的Class对象
Class<?> clazz = Class.forName("Person");
// 获取Person类的构造器
Constructor<?> constructor = clazz.getConstructor(String.class);
// 使用构造器创建一个新的Person对象
Object obj = constructor.newInstance("John");
// 获取sayHello方法
Method method = clazz.getMethod("sayHello", String.class);
// 调用sayHello方法
method.invoke(obj, "Hello");
}
}
反射优点:
反射缺点:
为什么反射执行的比较慢?
反射执行慢的主要原因是反射涉及到运行时类型检查,访问权限检查,动态方法调用和一些额外的操作。具体要经历以下过程:
二者最大的区别就是:静态代理是在编译期确定的代理类,动态代理是在运行时由JVM根据反射机制确定的代理类
动态代理的使用场景如下:
BIO、NIO、AIO时Java中的三种I/O模型,它们的区别主要体现在阻塞与非阻塞,同步与异步的两方面:
同步非阻塞和异步非阻塞的主要区别在于是否需要等待I/O操作完成:
关联:Exception和Error都是继承Throwable类,在Java中只有Throwable类型的实例,才可以throw异常或者catch异常,都是异常处理机制的基本组成类型
区别:
抽象类和接口有以下几种区别:
// 接口定义规范
public interface Flyable {
void fly();
}
public class Bird implements Flyable {
@Override
public void fly() {
System.out.println("Bird is flying.");
}
}
// 抽象类复用代码
public abstract class Animal {
public void eat() {
System.out.println("Animal is eating.");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("Dog is barking.");
}
}
Java中线程安全的包括Vector、Stack、BlockingQueue、Hashtable、ConcuurrentHashMap这几种,它们有很多方式来保证线程安全,如:
ArrayList和LInkedList是Java中List的两种实现,它们的主要区别有以下几种:
不同的JDK 版本,HashMap 的底层实现是不一样的,总体来说: 在JDK 1.8 之前不含JDK 1.8)HashMap 使用的是数组 + 链表实现的,而JDK 1.8 之后(包含JDK 18)使用的是数组 + 链表或红黑树实现的,当插入到同一个桶的数据过多的时候就会使用红黑树。