代理设计模式
代码示例
- 接口定义
java
// 定义一个服务接口
public interface Service {
void execute();
}
- 真实服务实现
java
// 真实服务类
public class RealService implements Service {
@Override
public void execute() {
System.out.println("执行真实服务逻辑");
}
}
- 静态代理
java
// 静态代理类
public class StaticProxy implements Service {
private Service realService;
public StaticProxy(Service realService) {
this.realService = realService;
}
@Override
public void execute() {
System.out.println("代理预处理逻辑");
realService.execute();
System.out.println("代理后处理逻辑");
}
}
- 动态代理(JDK 动态代理)
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 动态代理处理器
public class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理预处理逻辑");
Object result = method.invoke(target, args);
System.out.println("动态代理后处理逻辑");
return result;
}
public Object getProxy() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
}
- 测试代码
java
public class ProxyPatternTest {
public static void main(String[] args) {
// 静态代理测试
Service realService = new RealService();
StaticProxy staticProxy = new StaticProxy(realService);
staticProxy.execute();
// 动态代理测试
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(realService);
Service dynamicProxy = (Service) dynamicProxyHandler.getProxy();
dynamicProxy.execute();
}
}
企业面试题
-
静态代理和动态代理的区别是什么?
- 静态代理:代理类在编译期就已经确定,手动编写代理类代码,代理类和目标类实现相同接口,代理类中包含目标类的实例。
- 动态代理:代理类在运行期动态生成,通过反射机制实现。JDK 动态代理要求目标对象必须实现接口,CGLIB 动态代理可以代理没有实现接口的类,通过继承目标类生成代理类。
-
在什么情况下会选择使用代理设计模式?
- 远程代理:隐藏一个对象存在于不同地址空间的事实,比如 RMI(Remote Method Invocation)。
- 虚拟代理:当需要创建一个资源消耗较大的对象时,先创建一个消耗相对较小的代理对象,在真正需要时才创建真实对象,如加载大图片。
- 保护代理:控制对一个对象的访问,根据不同的权限决定是否允许访问真实对象。
企业实际应用场景
- Spring AOP(面向切面编程) :基于动态代理实现,用于在不修改目标对象代码的情况下,为其添加横切关注点,如日志记录、事务管理、权限控制等。
- RPC(Remote Procedure Call)框架:如 Dubbo,使用代理模式隐藏远程调用的细节,让调用者感觉像是在调用本地方法。
注解
代码示例
- 自定义注解
java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
String value() default "";
}
- 使用注解
java
public class AnnotationExample {
@MyAnnotation("这是一个示例注解")
public void annotatedMethod() {
System.out.println("执行被注解的方法");
}
}
- 解析注解
java
import java.lang.reflect.Method;
public class AnnotationParser {
public static void main(String[] args) {
AnnotationExample example = new AnnotationExample();
Class clazz = example.getClass();
try {
Method method = clazz.getMethod("annotatedMethod");
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
if (annotation != null) {
System.out.println("注解值: " + annotation.value());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
企业面试题
-
Java 注解的作用是什么?
- 编译检查:如
@Override注解,用于检查方法是否正确重写父类方法。 - 代码配置:在 Spring 框架中,使用注解进行 Bean 的定义和依赖注入,如
@Component、@Autowired等。 - 运行时处理:通过反射获取注解信息,实现特定的业务逻辑,如自定义权限控制注解。
- 编译检查:如
-
元注解有哪些,它们的作用是什么?
- @Retention:指定注解的保留策略,如
RetentionPolicy.RUNTIME(运行时保留)、RetentionPolicy.CLASS(编译时保留)、RetentionPolicy.SOURCE(源文件保留)。 - @Target:指定注解可以应用的目标元素类型,如
ElementType.METHOD(方法)、ElementType.TYPE(类、接口等)。 - @Documented:将注解包含在 Javadoc 中。
- @Inherited:允许子类继承父类的注解。
- @Retention:指定注解的保留策略,如
企业实际应用场景
- Spring 框架:广泛使用注解进行配置和依赖注入,简化了 XML 配置的繁琐。
- JUnit 测试框架:使用注解如
@Test标记测试方法,方便测试类的编写和执行。
前端 JS
代码示例
- 基本函数和变量
javascript
// 定义变量
let message = "Hello, World!";
// 定义函数
function greet() {
console.log(message);
}
greet();
- DOM 操作
html
JS DOM 示例
<div id="myDiv">原始文本</div>
修改文本
function changeText() {
let div = document.getElementById('myDiv');
div.textContent = "文本已修改";
}
- 事件监听
html
JS 事件监听示例
点击我
let button = document.getElementById('myButton');
button.addEventListener('click', function () {
alert('按钮被点击了');
});
企业面试题
-
JavaScript 中
let、const和var的区别是什么?var:函数作用域,存在变量提升,可重复声明。let:块级作用域,不存在变量提升,不可重复声明。const:块级作用域,不存在变量提升,不可重复声明,声明时必须初始化,且值不能重新赋值(对于对象和数组,可修改其内部属性和元素)。
-
什么是闭包,它有什么应用场景?
- 闭包:函数和其周围的状态(词法环境)的引用捆绑在一起形成闭包。
- 应用场景:实现数据封装和私有化,如模块模式;用于回调函数,保持状态。
企业实际应用场景
- 网页交互:实现按钮点击、表单验证、页面动态更新等交互功能。
- 单页应用(SPA)开发:如 Vue.js、React.js 等框架,使用 JavaScript 构建复杂的前端应用,提供流畅的用户体验。