面试官问我 String 为什么被 fianl 修饰

Posted 极品小學生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试官问我 String 为什么被 fianl 修饰相关的知识,希望对你有一定的参考价值。

我们先看下下图,被修饰的两个地方,类、字符数组 。我们从这两个出发回答这个问题。

被 final 修饰的 char[]

fianl 修饰变量表示改变量的值一旦被初始化后不可以修改。fianl 不论是修饰变量、参数、方法、类都表示其 是完美的不可以被修改,或者逻辑顺序不能改变是一个基本逻辑实现元素。

 final 的详细讲解可以看final详解


 

 那为什么这里要用final修饰呢?

被 fianl 修饰就表示不能被继承或者重写修改,String类的设计是Java设计者不希望程序员继承String也就说明String类的最好用法不是继承,而是依赖和关联的关系。

先说被fianl修饰的字符数组

字符串是我们在开发过程中要进程使用的,每一次的创建对象随着次数的增加都会造成资源的大量消耗,导致内存消耗以及庞大的性能开销,为了提高性能,降低内存消耗,提出了字符串共享的方案,在方法区的常量池中保存下创建唯一的字符串去共给不同的类不同的方法以及线程去使用。

再回到这个数组上,字符串共享是解决内存消耗以及性能开销的必然选择,这里还没回答出为什么要被final修饰。共享带来的问题就是安全问题,在多个线程对通同一个字符串访问操作是不确定的,为了保证线程安全并且兼顾内存资源问题最好的办法就是使用fianl修饰。表示禁止修改。

 

 类为什么也要被fianl修饰?

final修饰的类表示不可以被继承,就是限制多态/限制行为。Java的一大特性就是安全性,如果不被fianl修饰,在使用Sring的时候会有太多的不确定性,每一个方法都围绕char数组展开,如果被继承方法进行了多态,会造成不同的语义或者错误的定义,使得String的行为性不确定,使得String对象的代码将是不安全的,所以设计成不能被继承的,来保证它的绝对安全。也说明了这个类最好的使用方法是依赖和关联,而不是继承。

面试:阿里面试官问我设计模式——代理模式,我是这样回答的!

1.什么是代理模式? 为对象提供一种代理以控制对这个对象的访问。代理模式相当于:中介或者经纪人 ,代理类可以在被代理类的基础之上增加功能(扩展功能),比如日志记录和权限控制 ,这样被代理类隐藏起来了,比较安全。

1.代理模式实现方式有哪些?
静态代理和动态代理
2.静态代理是:需要程序员人为创建好代理类,缺点;如果被代理类很多的话,需要手写很多个代理类,代码会变得非常冗余。
3.静态代理实现方式有哪些?
1.通过继承2.实现接口

1.通过实现接口方式实现静态代理

1.定义共同接口

package com.mayikt.service;
public interface OrderService {

    /**
     * 共同抽象的方法
     */
    void order();
}

2.定义被代理类实现共同的接口

package com.mayikt.service.impl;

import com.mayikt.service.OrderService;

public class OrderServiceImpl implements OrderService {
    public void order() {
        System.out.println("执行订单业务逻辑代码");
    }
}

3.手写代理类OrderServiceProxy

package com.mayikt.service.proxy;

import com.mayikt.service.OrderService;
import com.mayikt.service.impl.OrderServiceImpl;
public class OrderServiceProxy implements OrderService {
    /**
     * 被代理对象
     */
    private OrderService orderService;

    public OrderServiceProxy(OrderService orderService) {
       this.orderService = orderService;
    }
    public void order() {
        System.out.println(">>>打印订单日志开始");
        orderService.order();
        System.out.println(">>>打印订单日志结束");
    }

}

4.测试

package com.mayikt.service;

import com.mayikt.service.cglib.proxy.CglibMethodInterceptor;
import com.mayikt.service.impl.OrderServiceImpl;
import com.mayikt.service.jdk.proxy.JdkInvocationHandler;
import com.mayikt.service.proxy.OrderServiceProxy;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;

public class Client {
    public static void main(String[] args) {
       OrderService orderService = new OrderServiceProxy(new OrderServiceImpl());
       orderService.order();
    }
}

通过继承的方式实现静态代理

1.定义共同接口

package com.mayikt.service;
public interface OrderService {

    /**
     * 共同抽象的方法
     */
    void order();
}

2.定义被代理类

package com.mayikt.service.impl;

import com.mayikt.service.OrderService;

public class OrderServiceImpl implements  OrderService{
    public void order() {
        System.out.println("执行订单业务逻辑代码");
    }
}

3.手写代理类

package com.mayikt.service.proxy;

import com.mayikt.service.OrderService;
import com.mayikt.service.impl.OrderServiceImpl;

public class OrderServiceProxy extends OrderServiceImpl {

    public void order() {
        System.out.println(">>>打印订单日志开始");
        super.order();// 执行父类的order 方法OrderServiceImpl
        System.out.println(">>>打印订单日志结束");
    }

}

4、测试

package com.mayikt.service;

import com.mayikt.service.cglib.proxy.CglibMethodInterceptor;
import com.mayikt.service.impl.OrderServiceImpl;
import com.mayikt.service.jdk.proxy.JdkInvocationHandler;
import com.mayikt.service.proxy.OrderServiceProxy;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;

public class Client  {
    public static void main(String[] args) {
        OrderService orderService = new OrderServiceProxy();
        orderService.order();
    }
}

动态代理

1.动态代理:不需要关心代理类, jvm运行的时候自动创建代理类,不需要手动创建。
2.动态代理实现方式有哪些?
jdk动态代理和cglib原理
3.jdk动态代理:jdk动态生成的代理类都是实现接口形式,所以被代理类必须实现接口(通过反射的方式实现)
cglib代理:通过asm字节码技术实现动态生成代理类,运行时动态的生成一个被代理类的子类
4.jdK动态代理要求被代理的类必须实现接口,当需要被代理的类没有实现接口时cglib代理是一个很好的选择
5.spring默认会使用JDK的动态代理,但是如果目标对象没有实现接口,则默认会采用CGLIB代理;

jdk实现动态代理

1.定义共同接口

package com.mayikt.service;
public interface OrderService {

    /**
     * 共同抽象的方法
     */
    void order();
}

2.定义被代理类实现共同的接口

package com.mayikt.service.impl;

import com.mayikt.service.OrderService;

public class OrderServiceImpl implements OrderService {
    public void order() {
        System.out.println("执行订单业务逻辑代码");
    }
}

3.创建生成动态代理类的类:JdkInvocationHandler

package com.mayikt.service.jdk.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkInvocationHandler implements InvocationHandler {
    /**
     * 被代理类对象 目标代理对象
     */
    private Object target;

    public JdkInvocationHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //执行方法前打印日志
        System.out.println(">>>jdk打印订单日志开始:proxy:"+proxy.getClass().toString());
        Object reuslt = method.invoke(target, args);// java的反射机制执行方法 执行目标对象的方法
        //执行方法后打印日志
        System.out.println(">>>jdk打印订单日志结束");
        return reuslt;
    }

    /**
     * 使用jdk动态代理创建代理类
     *
     * @param <T>
     * @return
     */
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

4.测试

package com.mayikt.service;

import com.mayikt.service.cglib.proxy.CglibMethodInterceptor;
import com.mayikt.service.impl.OrderServiceImpl;
import com.mayikt.service.jdk.proxy.JdkInvocationHandler;
import com.mayikt.service.proxy.OrderServiceProxy;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;

public class Client  {
    public static void main(String[] args) {
        // 1.使用jdk动态代理
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");//可以动态生成.class文件
        OrderService proxy = new JdkInvocationHandler(new OrderServiceImpl()).getProxy();
        proxy.order();

    }
}

使用cglib实现动态代理

     <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.12</version>
     </dependency>

2.定义被代理类

package com.mayikt.service.impl;

import com.mayikt.service.OrderService;

public class OrderServiceImpl {
    public void order() {
        System.out.println("执行订单业务逻辑代码");
    }
}

3.创建生成动态代理类的类:CglibMethodInterceptor

package com.mayikt.service.cglib.proxy;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibMethodInterceptor implements MethodInterceptor {
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println(">>>>cglib日志收集开始....");
        Object reuslt = proxy.invokeSuper(obj, args);
        System.out.println(">>>>cglib日志收集结束....");
        return reuslt;
    }
}

4.测试

package com.mayikt.service;

import com.mayikt.service.cglib.proxy.CglibMethodInterceptor;
import com.mayikt.service.impl.OrderServiceImpl;
import com.mayikt.service.jdk.proxy.JdkInvocationHandler;
import com.mayikt.service.proxy.OrderServiceProxy;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;

public class Client  {
    public static void main(String[] args) {
        // 使用cglib动态代理
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\code");//可以动态生成class文件
        CglibMethodInterceptor cglibMethodInterceptor = new CglibMethodInterceptor();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(OrderServiceImpl.class);
        enhancer.setCallback(cglibMethodInterceptor);
        OrderServiceImpl orderServiceImpl = (OrderServiceImpl) enhancer.create();
        orderServiceImpl.order();

    }
}

总结:看完有什么不懂的话欢迎在下方留言评论,记得点个赞哦!

以上是关于面试官问我 String 为什么被 fianl 修饰的主要内容,如果未能解决你的问题,请参考以下文章

美团面试官问我一个字符的String.length()是多少,我说是1,面试官说你回去好好学一下吧

面试:阿里面试官问我设计模式——代理模式,我是这样回答的!

面试:阿里面试官问我设计模式——代理模式,我是这样回答的!

面试:阿里面试官问我设计模式——代理模式,我是这样回答的!

面试:阿里面试官问我设计模式——代理模式,我是这样回答的!

面试官问我:一个 TCP 连接可以发多少个 HTTP 请求?我竟然回答不上来