1. Java中的#{}
和${}
的区别是什么?
答案: #{}
和${}
在Java中主要用于模板引擎或框架中,如MyBatis等,它们的区别如下:
-
${}
:-
是OGNL表达式的一部分,用于直接替换变量值。
-
不会进行类型转换,直接将变量的值作为字符串拼接到SQL语句中。
-
如果变量值为
null
,可能会导致SQL语句拼接错误。
-
-
#{}
:-
是MyBatis的占位符,用于预编译SQL语句。
-
支持类型转换,会将变量值作为参数传递给预编译的SQL语句。
-
如果变量值为
null
,会自动处理为NULL
,避免SQL语句出错。
-
适用场景:
-
使用
${}
时,需要确保变量值不为null
,且拼接后的SQL语句语法正确。 -
使用
#{}
时,更适合处理可能为null
的变量,同时支持预编译,提高SQL执行效率。
2. Java中如何实现动态代理?
答案: 动态代理是一种在运行时动态生成代理类的技术,通常用于实现AOP(面向切面编程)。Java中可以通过java.lang.reflect.Proxy
类和InvocationHandler
接口来实现动态代理。
实现步骤:
-
定义接口: 定义一个接口,声明需要代理的方法。
java复制
public interface MyService { void doSomething(); }
-
实现
InvocationHandler
接口: 创建一个InvocationHandler
实现类,用于处理代理方法的调用。java复制
import java.lang.reflect.*; public class MyInvocationHandler implements InvocationHandler { private final Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在方法调用前后添加逻辑 System.out.println("Before method: " + method.getName()); Object result = method.invoke(target, args); System.out.println("After method: " + method.getName()); return result; } }
-
生成代理对象: 使用
Proxy.newProxyInstance()
方法动态生成代理对象。java复制
public class DynamicProxyDemo { public static void main(String[] args) { MyService target = new MyServiceImpl(); // 目标对象 MyInvocationHandler handler = new MyInvocationHandler(target); MyService proxy = (MyService) Proxy.newProxyInstance( MyService.class.getClassLoader(), // 目标类的类加载器 new Class<?>[]{MyService.class}, // 目标类实现的接口 handler // InvocationHandler实例 ); proxy.doSomething(); // 调用代理方法 } }
应用场景:
-
动态代理常用于Spring的AOP功能,如事务管理、日志记录等。
3. Java中String
为什么是不可变的?
答案: String
在Java中是不可变的,这意味着一旦创建了一个String
对象,它的内容就不能被修改。
原因:
-
线程安全:
-
不可变性使得
String
对象在多线程环境中不需要额外的同步措施,因为它的状态不会改变。
-
-
性能优化:
-
JVM可以利用字符串常量池,对相同的字符串值进行共享,减少内存占用。
-
-
安全性:
-
不可变性使得
String
对象可以被用作类加载器的加载路径或作为HashMap
的键,确保其值不会被意外修改。
-
实现原理:
-
String
类的内部使用一个字符数组char[]
来存储字符串内容,该数组被声明为final
,且在构造函数中初始化后无法修改。 -
所有修改字符串的操作(如
substring()
、concat()
等)都会返回一个新的String
对象。
示例:
java复制
String str1 = "Hello";
String str2 = str1.concat(" World");
System.out.println(str1); // 输出 "Hello",原字符串未被修改
System.out.println(str2); // 输出 "Hello World",返回了新的字符串对象