学习总结(1) JAVA 基础

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hesiyuanlx/article/details/82147514

从接触java至今日已经一年有余,从今日开始每日总结一些遇到的问题及其解决方法,用以回顾备忘。

 1.  0.1*3 == 0.3 ?

 结果为:false 

 浮点数加法会出现精度问题,正确做法可以参考下文,建议是先转为int 做完运算后再还原。

 https://blog.csdn.net/haihuan2004/article/details/52900909

2.  Java 中的构造器链是什么?

多个构造方法,少参数的加上默认参数调用复杂参数的,这一现象在各开源框架中常见。

以对象池org.apache.commons.pool.impl.GenericObjectPool<T> 为例,共有N个构造器,简单构造器添加相应的默认参数调用复杂构造器:


public class GenericObjectPool<T> extends BaseObjectPool<T> implements ObjectPool<T> {
ate a new <tt>GenericObjectPool</tt> with default properties.

     */
    public GenericObjectPool() {
        this(null, DEFAULT_MAX_ACTIVE, DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE,
                DEFAULT_MIN_IDLE, DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
                DEFAULT_NUM_TESTS_PER_EVICTION_RUN, DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
    }


    public GenericObjectPool(PoolableObjectFactory<T> factory) {
        this(factory, DEFAULT_MAX_ACTIVE, DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE,
                DEFAULT_MIN_IDLE, DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
                DEFAULT_NUM_TESTS_PER_EVICTION_RUN, DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
    }


    public GenericObjectPool(PoolableObjectFactory<T> factory, GenericObjectPool.Config config) {
        this(factory, config.maxActive, config.whenExhaustedAction, config.maxWait, config.maxIdle, config.minIdle,
                config.testOnBorrow, config.testOnReturn, config.timeBetweenEvictionRunsMillis, 
                config.numTestsPerEvictionRun, config.minEvictableIdleTimeMillis, config.testWhileIdle, 
                config.softMinEvictableIdleTimeMillis, config.lifo);
    }


    public GenericObjectPool(PoolableObjectFactory<T> factory, int maxActive) {
        this(factory, maxActive, DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE, DEFAULT_MIN_IDLE,
                DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
                DEFAULT_NUM_TESTS_PER_EVICTION_RUN, DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
    }

    public GenericObjectPool(PoolableObjectFactory<T> factory, int maxActive, byte whenExhaustedAction, long maxWait) {
        this(factory, maxActive, whenExhaustedAction, maxWait, DEFAULT_MAX_IDLE, DEFAULT_MIN_IDLE, DEFAULT_TEST_ON_BORROW,
                DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
                DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
    }

    
    public GenericObjectPool(PoolableObjectFactory<T> factory, int maxActive, byte whenExhaustedAction, long maxWait,
            boolean testOnBorrow, boolean testOnReturn) {
        this(factory, maxActive, whenExhaustedAction, maxWait, DEFAULT_MAX_IDLE, DEFAULT_MIN_IDLE, testOnBorrow,
                testOnReturn, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
                DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
    }

    public GenericObjectPool(PoolableObjectFactory<T> factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle) {
        this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, DEFAULT_MIN_IDLE, DEFAULT_TEST_ON_BORROW,
                DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
                DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
    }


    public GenericObjectPool(PoolableObjectFactory<T> factory, int maxActive, byte whenExhaustedAction, long maxWait,
            int maxIdle, boolean testOnBorrow, boolean testOnReturn) {
        this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, DEFAULT_MIN_IDLE, testOnBorrow, testOnReturn,
                DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
                DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
    }

  
    public GenericObjectPool(PoolableObjectFactory<T> factory, int maxActive, byte whenExhaustedAction, long maxWait,
            int maxIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis,
            int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
        this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, DEFAULT_MIN_IDLE, testOnBorrow, testOnReturn,
                timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle);
    }

  
    public GenericObjectPool(PoolableObjectFactory<T> factory, int maxActive, byte whenExhaustedAction, long maxWait,
            int maxIdle, int minIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis,
            int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
        this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, minIdle, testOnBorrow, testOnReturn,
                timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle,
                DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
    }

  

3.  Switch 中使用 String 注意项:

从 Java 7 开始,我们可以在 switch case 中使用字符串,但这仅仅是一个语法糖。内部实现在 switch 中使用字符串的 hash code。

4.  WeakHashMap 常用场景?

因为当key对象不在被引用时,key / value 会被清楚,适用于请求进入后的该笔数据暂存,在处理线程使用完毕后清除,非常适用于缓存。

5.  Objcet 的 hashcode 与 equal 函数原理?

对象equal 常用于字符串比较,对象比较时,对应元素比较 建议重写。重写的同时也重写hashcode。

6.  poll() 方法和 remove() 方法的区别?

poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空,但是 remove() 失败的时候会抛出异常。

7.  两个数字交换,不使用temp内存?

a' = a^b 此时求出的是a与b不相同的部分 a'代表着a与b 2进制中不相同的位

b = b^a' 此时将b与a'  2进制中不相同的位求反 于是b变成了 a。

a = b^a 此时将b 中与a'不相同的位求反 于是 b^a' 变为了原本的a。

8.  a = a + b 与 a += b 的区别

+= 隐式的将加操作的结果类型强制转换为持有结果的类型。如果两这个整型相加,如 byte、short 或者 int,首先会将它们提升到 int 类型,然后在执行加法操作。

9.  对于对象的成员中有对象时,成员需要拷贝。

class A {
    private int b = 1;
    private String c = "1";
    private Object d = new Object a;

    private Object clone() {
        A a  = new A();
        a.d = d.clone();
        return a;
    }
}

10.   缓存淘汰算法--LRU算法

固定大小的LinkedHashMap,removeEldestEntry触发移除key的 当前size大于了设置的缓存大小 。

或者采用hashmap,命中+1,当当前map的容量大于一定时,扫描全部key的value 取最小的移除。

还有个更快现成的,使用redis.......

import java.util.ArrayList;  
import java.util.Collection;  
import java.util.LinkedHashMap;  
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;  
import java.util.Map;  


/** 
 * 类说明:利用LinkedHashMap实现简单的缓存, 必须实现removeEldestEntry方法,具体参见JDK文档 
 *  
 * @author dennis 
 *  
 * @param <K> 
 * @param <V> 
 */ 
public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {  
    private final int maxCapacity;  

    private static final float DEFAULT_LOAD_FACTOR = 0.75f;  

    private final Lock lock = new ReentrantLock();  

    public LRULinkedHashMap(int maxCapacity) {  
        super(maxCapacity, DEFAULT_LOAD_FACTOR, true);  
        this.maxCapacity = maxCapacity;  
    }  

    @Override 
    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {  
        return size() > maxCapacity;  
    }  
    @Override 
    public boolean containsKey(Object key) {  
        try {  
            lock.lock();  
            return super.containsKey(key);  
        } finally {  
            lock.unlock();  
        }  
    }  


    @Override 
    public V get(Object key) {  
        try {  
            lock.lock();  
            return super.get(key);  
        } finally {  
            lock.unlock();  
        }  
    }  

    @Override 
    public V put(K key, V value) {  
        try {  
            lock.lock();  
            return super.put(key, value);  
        } finally {  
            lock.unlock();  
        }  
    }  

    public int size() {  
        try {  
            lock.lock();  
            return super.size();  
        } finally {  
            lock.unlock();  
        }  
    }  

    public void clear() {  
        try {  
            lock.lock();  
            super.clear();  
        } finally {  
            lock.unlock();  
        }  
    }  

    public Collection<Map.Entry<K, V>> getAll() {  
        try {  
            lock.lock();  
            return new ArrayList<Map.Entry<K, V>>(super.entrySet());  
        } finally {  
            lock.unlock();  
        }  
    }  
}  

11.  在List移除元素的时候,List 的get(i) 和 for each

更建议使用for each..因为移除了一个元素后,List下标会产生变化。

12.  Mybatis的代理类,想要在创建时截获其在spring中id,其名字为类名首字母大写 与其他spring类默认名不同。

其他第三方框架注入sping时,其默认的id为类名小写开头的驼峰命名原则。 例如testService。

而mybatis 注入sping时的默认id为大写开头。

例为:   TestDao$312451

这个问题在监听spring容器创建mybatis类时,想在外面添加装饰器,捕获该类老失败。发现命名不同。

13.   Mybatis如果实现了事务,事务的注解在接口上时,那么注意了,注入该类的实现时,一定要以接口的方式注入,否则会报类类型转换失败。因为mybatis注入的是代理sun.proxy 而不是你原本实现该事务接口类的类型。

interface A {
    @Transactional(value = "transactionManager", isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
    void test(@ShardParam("dbParam") RecordOrderDto recordOrderDto, List<TicketDto> ticketDtos)
            throws RecorderException;
}

@Service("b")
class B implements A {
    
    @Autowired
    prvaite interfaceDao dao;
    
    public void test() {
    dao.insert()
}

}

class c {
    /**
    *这种注入方式会报类型错误
    *
    /
    @Autowired
    private B b;

    /**
    * 正确做法
    /
    @Autowired
    @Qualifier("b")
    private A b;
}

14  HashTable 与 HashMap ,很多总说HashTable线程不安全,HashMap 线程安全,是这样的吗

HashTable 已经不推荐使用了,不使用。

ConcurrentHashMap 采用了分段锁。get和put是原子操作,所以线程安全。

HashMap的每个节点与ConcurrentHashMap 的每个分片下的节点,在jdk1.8之后改为了红黑树。

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

无论采用这两种结构,在使用读取变量修改填回时,一定要在外面加锁。

例如:

get(a)

value a=a+1

put(a)

因为HashMap仅仅保证get 和put是原子操作,但是由于多并发下,这种从map中读值再修改填写回去的时候,会出现覆盖。

15.  HashMap与ConcurrentHashMap 在其他地方看到,在多线程下并发下,会因为resize导致死锁,所以给这种map在初始化时,添加一个好的初始值,让数据均匀分布,减少扩容的次数是非常好的习惯。

不知道扩容这个导致两个线程同时rehash导致的循环链表死锁问题在jdk1.8.0里面修复没有,目前采用红黑树,应该没有了才对。待验证~~!!!

参考文章:https://blog.csdn.net/V_Axis/article/details/78604505

16.  java 32位虚拟机和64位虚拟机中的int 

没有区别 int都是32位的,但是因为寻址地址从32->64堆大小根据虚拟机支持 可以调到很大很大了,不过32位项目迁移64位时,因为帧大小的扩充会占用缓存大增,记得调节jvm的UseCompressedOops进行指针压缩,减少缓存。

参考文章:https://blog.csdn.net/zjerryj/article/details/77206928

17.  什么是内存屏障(Memory Barrier)?

内存屏障(memory barrier)是一个CPU指令。基本上,它是这样一条指令: a) 确保一些特定操作执行的顺序; b) 影响一些数据的可见性(可能是某些指令执行后的结果)。编译器和CPU可以在保证输出结果一样的情况下对指令重排序,使性能得到优化。插入一个内存屏障,相当于告诉CPU和编译器先于这个命令的必须先执行,后于这个命令的必须后执行。内存屏障另一个作用是强制更新一次不同CPU的缓存。

个人:在这个命令前所以命名必须执行完,防止重排序的坑,同时强制更新cpu缓存。

18.  计算无符号32位数中,2进制中1的个数。

一篇非常有趣的文档:https://www.cnblogs.com/graphics/archive/2010/06/21/1752421.html

展开阅读全文

没有更多推荐了,返回首页