Java工程师面试1000题111-120

111、说说你对Java中反射的理解。

Java中的反射是可以让我们在运行时获取类的方法、属性、父类、接口等类的内部信息的机制。也就是说,反射本质上是一个“反着来”的过程。我们通过new创建一个类的实例的时候,实际上是由Java虚拟机根据这个类的Class对象在运行时构建出来的,而反射是通过一个类的Class对象来获取它的定义信息,从而我们可以访问到它的属性、方法,知道这个类的父类、实现哪些接口等信息。

Java中的反射首先是能够获取到Java中要反射类的字节码,获取字节码有三种方法:1、Class.forName(className) 2、类名.class 3、this.getClass()。然后将字节码中的方法、变量、构造函数等映射成相应的Method、Filed、Constructor等类,这些类提供了丰富的方法可以被我们所使用。

112、静态代理和动态代理的区别?什么场景使用?

静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。

静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。

动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。还有一种动态代理CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的。

AOP编程就是基于动态代理实现的,比如著名的Spring框架就是动态代理的使用例子。

113、说出你所知道的设计模式。

总的来说设计模式分为三大类:

创建型模式:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式,访问者模式、中介者模式、解释器模式。

Java中一般认为有如上23种设计模式,我们不需要所有都会,但是其中常用的几种设计模式应该要掌握。下面几道题分别简介一下几种常用的设计模式。

114、简单介绍一下单例设计模式。

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,根据对象创建的时间分为懒汉式和饿汉式。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

饿汉式:

public class Singleton{

    //直接创建对象实例
    public static Singleton instance = new Singleton();

    //私有构造函数
    private Singleton(){}

    //返回对象实例
    public static Singleton getInstance(){
        return instance;
    }
}

懒汉式:

public class Singleton{

    //声明变量
    private static volatile Singleton singleton = null;

    //私有构造函数
    private Singleton(){}

    //提供对外的方法
    public static Singleton getInstance(){

        if(singleton == null){
            synchronized(Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

115、介绍一下工厂设计模式。

工厂设计模式分为工厂方法模式和抽象工厂模式。

①工厂方法模式又可分为:普通工厂模式、多个工厂方法模式、静态工厂方法模式。

普通工厂模式就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。

public interface Sender{
    public void Send();
}
----------------------------------------------------------
public class MailSender implements Sender{
    @Override
    public void Send(){
        System.out.println("this is a mail sender");
    }
}
----------------------------------------------------------
public class SmsSender implements Sender{
    @Override
    public void Send(){
        System.out.println("this is a sms sender");
    }
}
----------------------------------------------------------
public class SendFactory{
    public Sender produce(String type){
        if("mail".equals(type)){
            return new MailSender();
        }else if("sms".equals(type)){
            return new SmsSender();
        }else{
            System.out.println("请输入正确的类型");
            return null;
        }
    }
}

多个工厂方法模式是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。

public class SendFactory{
    public Sender produceMail(){
       return new MailSender();
    }
    public Sender produceSms(){
       return new SmsSender();
    }
}
---------------------------------------------------
public class FactoryTest{
    public static void main(String[] args){
        SendFactory factory = new SendFactory();
        Sender sender = factory.produceMail();
        sender.send();
    }
}

将上面的多个工厂方法模式里的方法设置为静态的,不需要创建实例,直接调用即可。

public class SendFactory{
    public static Sender produceMail(){
       return new MailSender();
    }
    public static Sender produceSms(){
       return new SmsSender();
    }
}
---------------------------------------------------
public class FactoryTest{
    public static void main(String[] args){
        Sender sender = SendFactory.produceMail();
        sender.send();
    }
}

②抽象工厂模式:工厂方法模式有一个问题就是类的创建依赖工厂类,也就是说如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以从设计角度,有一定问题,如何解决?那就需要用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

public interface Provider{
    public Sender produce();
}
-----------------------------------------------------
public interface Sender{
    public void send();
}
-----------------------------------------------------
public class MailSender implements Sender{
    @Override
    public void send(){
        System.out.println("this is a mail sender");
    }
}
-----------------------------------------------------
public class SmsSender implements Sender{
    @Override
    public void send(){
        System.out.println("this is a sms sender");
    }
}
-----------------------------------------------------
public class SendSmsFactory implements Provider{
    @Override
    public Sender produce(){
        return new SmsSender();
    }
}
-----------------------------------------------------
public class SendMailFactory implements Provider{
    @Override
    public Sender produce(){
        return new MailSender();
    }
}
-----------------------------------------------------
-----------------------------------------------------
public class Test{
    public static void main(String[] args){
        Provider provider = new SendMailFactory();
        Sender sender = provider.produce();
        sender.send();
    }
}

116、说一下JVM垃圾回收机制和常见算法

理论上来讲Sun公司只定义了垃圾回收机制规则而不局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同。GC(Garbage Collector)在回收对象之前首先必须发现那些无用的对象,如何去发现和定位那些无用的对象?常见的搜索算法有引用计数器算法(已废弃)和根搜索算法(在使用)。

引用计数器算法:引用计数器算法是给每个对象设置一个计数器,当有地方引用这个对象的时候,计数器加一,当引用失效的时候,计数器-1,当计数器为0的时候,JVM就认为对象不再被使用,是“垃圾”了。引用计数器实现简单,效率高,但是不能解决循环引用的问题(A对象引用B对象,B对象又引用A对象,但是A,B对象已不被任何其他对象引用),同时每次计数器的增加和减少都会带来很多额外的开销。所以在JDK1.1之后,这个算法就被抛弃不再使用了。

根搜索算法:根搜索算法是通过一些“GC Roots”对象作为起点,从这些节点开始往下搜索,搜索通过的路径成为引用链(Reference Chain),当一个对象没有被GC Roots的引用链连接的时候,说明这个对象是不可用的了。

GC Roots对象可以是:

  • 虚拟机栈(栈帧中的本地变量表)中的引用的对象
  • 方法区域中的类静态属性引用的对象。
  • 方法区域中常量引用的对象
  • 本地方法栈中JNI(Native方法)的引用的对象

117、说一下垃圾回收算法中的标记-清除算法。

标记-清除算法(Mark-Sweep)包括两个阶段:“标记”和“清除”。在标记阶段,确定所有要回收的对象,并做标记。清除阶段紧随标记阶段,将标记阶段确定不可用的对象清除。标记-清除算法是基础的收集算法,标记和清除阶段效率不高,而且清楚后会产生大量不连续空间,这样当程序员需要分配大内存对象的时候,可能无法找到足够的连续空间。

118、说一下垃圾回收算法中的复制算法。

复制算法是把内存分成大小相等的两块,每次使用其中的一块,当垃圾回收的时候,把存活的对象复制到另一块上,然后把这块内存整个清理掉。复制算法实现简单、运行效率高,但是由于每次只能使用其中的一半,造成内存的利用率不高,现在的JVM用复制算法收集新生代,由于新生代大部分对象(98%)都是朝生夕死的,所以两块内存的比例不是1:1(大概是8:1)。

119、说一下垃圾回收算法中的标记-整理算法

标记-整理算法和标记-清除算法一样,但是标记-整理算法不是把存活对象复制到另一块内存,而是把存活对象往内存的一端移动,然后直接回收边界以外的内存,标记-整理算法提高了内存的利用率,并且它适合在收集对象存活时间较长的老年代。

120、说一下垃圾回收算法中的分代搜集算法

分代收集算法是根据对象的存活时间把内存分为新生代和老年代,根据各个代对象的存活特点,每个代采用不同的垃圾回收算法。新生代采用复制算法,老年代采用标记-整理算法。垃圾收集算法的实现涉及大量的程序细节,而且不同的虚拟机平台实现的方法也各不相同。

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值