欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Java程序员必知必会的90个细节,Java开发工程师面试问题大全

程序员文章站 2022-06-04 23:21:41
...

幸运的是,还有第三种替代方法。它既能像重叠构造器模式的安全性,又能保证像JavaBeans模式那样的可读性。这就是建造者模式。


package com.guor.effective.chapter2.worker;



public class Worker {

    private int id;

    private String name;



    private int age;

    private int sex;

    private String school;

    private String address;



    public static class Builder{

        private int id;

        private String name;



        private int age = 18;

        private int sex = 1;

        private String school = "辽宁石油化工大学";

        private String address = "辽宁省大连市高新园区";



        public Builder(int id, String name) {

            this.id = id;

            this.name = name;

        }



        public Builder age(int val){

            age = val;

            return this;

        }



        public Builder sex(int val){

            sex = val;

            return this;

        }



        public Builder school(String val){

            school = val;

            return this;

        }



        public Builder address(String val){

            address = val;

            return this;

        }



        public Worker build() {

            return new Worker(this);

        }

    }



    public Worker(Builder builder){

        int id = builder.id;

        String name = builder.name;



        int age = builder.age;

        int sex = builder.sex;

        String school = builder.school;

        String address = builder.address;

    }



    @Override

    public String toString() {

        return "Worker{" +

                "id=" + id +

                ", name='" + name + '\'' +

                ", age=" + age +

                ", sex=" + sex +

                ", school='" + school + '\'' +

                ", address='" + address + '\'' +

                '}';

    }

} 

package com.guor.effective.chapter2.worker;

public class Test {

public static void main(String[] args) {

    Worker worker = new Worker

            .Builder(1,"郭晓彤").age(1).sex(1).school("中铁诺德幼儿园")

            .address("中铁诺德滨海花园").build();

    System.out.println(worker.toString());

}

}




第3条:用私有构造器或者枚举类型强化Singleton属性

=============================



第4条:通过私有构造器强化不可实例化的能力 

======================



package com.guor.effective.chapter2.test;

public class Test2 {

private Test2(){

    System.out.println("我是一个私有构造器");

}



public static void constructor() {

    System.out.println("我是一个工具类");

}

}




![](https://img-blog.csdnimg.cn/20200814141405917.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2d1b3J1aV9qYXZh,size_16,color_FFFFFF,t_70)



第5条:优先考虑依赖注入来引用资源

=================



第6条:避免创建不必要的对象

==============



1、自动装箱

------



创建多余对象的方法,有一种叫自动装箱,它允许程序员将基本类型和封装类型混用,按需要自动装箱和拆箱。自动装箱使得基本类型和装箱基本类型之间的差别变得模糊起来,但是并没有完全消除,它们在语义上还有着微妙的差别,在性能上也有着明显的差别。



举例说明,计算所有int正整数值的总和。



(1)基本类型性能测试



package com.guor.effective.chapter2.test;

public class getIntSum {

public static void main(String[] args) {

    long a= System.currentTimeMillis();//获取当前系统时间(毫秒)

    long sum = 0;

    for (int i = 0; i < Integer.MAX_VALUE; i++) {

        sum += i;

    }

    System.out.println("int正整数之和:"+sum);

    System.out.println("程序执行时间为:"+(System.currentTimeMillis()-a)+"毫秒");

}

}




![](https://img-blog.csdnimg.cn/20200815114144385.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2d1b3J1aV9qYXZh,size_16,color_FFFFFF,t_70)



### (2)封装类型性能测试 



![](https://img-blog.csdnimg.cn/20200815114346970.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2d1b3J1aV9qYXZh,size_16,color_FFFFFF,t_70)



Long比long时间差的还是挺悬殊的。要优先使用基本类型,而不是封装类型,要当心无意识的自动装箱。



2、创建有意义的小对象

-----------



不要错误的认为此条所介绍内容暗示着“创建对象的代价非常昂贵,我们应该尽可能的创建对象”。相反,由于小对象的构造器只做少量的显示工作,所以小对象的创建和回收工作是非常廉价的,特别是在现代的JVM实现上更是如此。通过创建附加的对象提升程序的清晰性、简洁性、功能性,这通常是件好事。反之,通过维护自己的对象池来避免创建对象,并不是一种好的做法,除非池中的对象是非常重量级的,正确使用对象池的典型示例就是数据库连接池。建立数据库连接的代价是非常昂贵的,因此重用这些对象非常有意义。一般而言,维护自己的对象池,一般会将代码变得很乱,同时增加内存占用,而且还会损害性能。现代的JVM实现具有高度优化的垃圾回收器,其性能很容易就会超过轻量级对象池的性能。



第7条:消除过期的对象引用

=============



1、自己管理内存

--------



只要类时自己管理内存,程序员就应该警惕内存泄漏问题。一旦元素被释放,该元素中包含的任何对象引用都应该被清空。



2、内存泄漏的另一种常见来源是缓存。

------------------



一旦把对象放到缓存中,就有可能被遗忘,长时间留在缓存中。对于这个问题,可以使用WeakHashMap代表缓存,当缓存中的项过期之后,它们就会自动被删除。记住只有当所要的缓存项的生命周期是由该键的外部引用而不是由值决定时,WeakHashMap才有用处。



3、内存泄漏的第三种来源是监听器和其它回调

---------------------



如果你实现一个API,客户端在这个API中注册回调,却没有显示地取消注册,那么除非你采取某些动作,否则它们就会不断地堆积起来。确保回调立即被当做垃圾回收的最佳方法是只保存它们的弱引用,例如,只讲它们保存成WeakHashMap中的键。



由于内存泄漏不会表现成明显的失败,所以它们可以在一个系统中存在很多年。往往通过仔细检查代码,或者借助于Heap剖析工具(Heap Profiler)才能发现内存泄漏问题。因此,如果能够在内存泄漏发生之前就知道如何预测此类问题,并阻止它们发生,那是最好不过的了。



第8条:避免使用终结方法和消除方法

=================



1、终结方法和消除方法

-----------



终结方法通常是不可预测的,也是很危险的,一般情况下是不必要的。



消除方法没有终结方法那么危险,但仍然是不可预测、运行缓慢,一般情况下也是不必要的。



2、永远不应该依赖终结方法或消除方法来更新重要的持久状态。

-----------------------------



3、终结方法finalize()

----------------



finalize()是Object中的方法,当垃圾回收器将要回收对象所占内存之前被调用,即当一个对象被虚拟机宣告死亡时会先调用它finalize()方法,让此对象处理它生前的最后事情(这个对象可以趁这个时机挣脱死亡的命运)。



虽然以上以对象救赎举例,但finalize()的作用往往被认为是用来做最后的资源回收。  

基于在自我救赎中的表现来看,此方法有很大的不确定性(不保证方法中的任务执行完)而且运行代价较高。所以用来回收资源也不会有什么好的表现。



4、终结方法攻击

--------



> 终结方法攻击:

> 

> 如果从构造器或者它的序列化对等体抛出异常,恶意子类的终结方法就可以在构造了一部分的应该已经半途而废的对象上运行。这个终结方法会将对该对象的引用记录在一个静态域中,阻止它被垃圾回收。一旦记录到异常的对象,就可以轻松地在这个对象上调用任何原本永远不允许在这里出现的方法,这种方法的调用就是终结方法攻击。final类不会受到终结方法攻击,因为没有人能够写出final类的恶意子类。为了防止非final类受到终结方法攻击,要编写一个空的final的finalize方法。



5、try-with-resources

--------------------



既然存在终结方法攻击,一般可以让类实现AutoCloseable,并要求器客户端在每个实例不再需要的时候调用close方法,一般利用try-with-resources确保终止。



6、那么终结方法和消除方法有什么好处呢?

--------------------



(1)当close忘记被调用时,终结方法或消除方法可以充当“安全网”。



(2)回收本地对等体。



> 本地对等体是一个本地对象,普通对象通过本地方法委托给一个本地对象。因为本地对等体不是一个普通对象,因此不能被垃圾回收,此时可以用终结方法或消除方法进行回收。



第9条:try-with-resources优先于try-fanally


### 笔者福利

##### 以下是小编自己针对马上即将到来的金九银十准备的一套“面试宝典”,不管是技术还是HR的问题都有针对性的回答。

**有了这个,面试踩雷?不存在的!**

##### 需要这套“面试宝典”的,[点击这里即可免费获取](https://gitee.com/vip204888/java-p7)!回馈粉丝,诚意满满!!!

![](https://img-blog.csdnimg.cn/img_convert/708d4b175dac64861e53d09bdbbb139e.png)
![](https://img-blog.csdnimg.cn/img_convert/541342a4477c3b36b6ae8578c5d80331.png)
![](https://img-blog.csdnimg.cn/img_convert/610677ce4fc6586452b3ec3aef0b8769.png)
本地对等体。



> 本地对等体是一个本地对象,普通对象通过本地方法委托给一个本地对象。因为本地对等体不是一个普通对象,因此不能被垃圾回收,此时可以用终结方法或消除方法进行回收。



第9条:try-with-resources优先于try-fanally


### 笔者福利

##### 以下是小编自己针对马上即将到来的金九银十准备的一套“面试宝典”,不管是技术还是HR的问题都有针对性的回答。

**有了这个,面试踩雷?不存在的!**

##### 需要这套“面试宝典”的,[点击这里即可免费获取](https://gitee.com/vip204888/java-p7)!回馈粉丝,诚意满满!!!

[外链图片转存中...(img-mYODOeTK-1628597661132)]
[外链图片转存中...(img-FdNTQxtY-1628597661134)]
[外链图片转存中...(img-n3VT0HEI-1628597661136)]
![](https://img-blog.csdnimg.cn/img_convert/5131d43a9636af0bdaccd501d43ca880.png)