Java 相关概念总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zx711166/article/details/84846718
8种基础数据类型的大小、封装类
类型 封装类 位数 表现形式
double Double 8位 0.0d
float Float 4位 0.0f
long Long 8位 0L
int integer 4位 0
short Shor 2位 (short) 0
byte byte 1位 (byte) 0
char Character 2位 null \u0000
boolean Boolean false
基础数据类型、引用数据类型的区别
数据类型 所属 区别
基础数据类型 double、float、long、int、short、byte、char、boolean(8种基础类型) 所有的简单数据类型不存在“引用”的概念,基础数据类型都是直接存储在内存栈上,数据北盛的值就是存储在栈空间里
引用数据类型 类、接口、数组(3种引用类型) 引用类型继承了Object类(引用类型),按照Java内存储内向的内存模型来进行数据存储,使用Java内存堆和内存栈进行存储;“引用”是存储在有序的内存栈上,而对象本身的值存储在内存堆上
Java(OOP)面向对象的三个特征与定义
  • 封装:可见性封装,set、get读写,将类的某些特征隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
  • 继承:子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),java中的多继承可以通过接口来实现。
  • 多态:
    • 编译时多态:通过方法的重载类实现。
    • 运行时多态:通过方法的重写来实现。
重写和重载的含义与区别
  • 重写:是子类覆盖父类方法,重新定义;
    • 但是返回类型、参数、参数类型、抛出异常都和父类一致;
    • 被覆盖的方法不能private,子类函数访问权限要大于等于父类;
    • 子类无法覆盖父类的static方法或private方法。
  • 重载:是一个类中,方法名相同;但是具有不同程度程度参数类型、不同的参数个数、不同的参数顺序。
Interface、abstract的区别
区别 abstract(抽象类) Interface(接口)
构造方法 可以包含 不能包含
不同成员变量 可以包含 不能包含
非抽象的普通方法 可以包含 不能包含
抽象方法访问类型 public、protected、默认类型 public
静态方法 可以包含 不能包含
静态成员变量 可以包含、访问类型随意 可以包含、方位类型只能是public static final
实现情况 一个类只能继承一个抽象类 一个类可以实现多个接口
static class、non static class的区别(Java多态的实原理)
区别 静态内部类(static class) 非静态内部类(non static class)
指向外部的引用 不需要 需要
访问成员 不能访问外部类的非静态成员
只能访问外部类的静态成员
能够访问外部类的静态和非静态成员
/ 一个非静态内部类不能脱离外部类实体被创建
/ 一个非静态内部类可以访问外部类的数据和方法,因为它就在外部内里
foreach、正常for循环效率对比
处理类型 效率for
数组 效率大致相同 效率大致相同
链表 效率低 效率高
switch支持的参数类型
JDK版本 支持类型
Jdk1.7以前 byte、short、char、int
Jdk1.7以后 byte、short、char、int、整形、枚举型、boolean、字符串
equals 与 == 的区别
类型 区别 原因
== == 比较的是两个对象的地址 == 比较的是变量内存(栈)中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指同一个对象;比较的是真正意义上的指针操作。
equals equals 比较的是两个对象的内容 equals 比较的是两个对象的内容是否相同,由于所有的类都继承自 java.lang.Object 类,所以适用于所有对象。如果没有对该方法进行覆盖的话,调用的依然是 Object 类中的方法,而 Object 中的 equals 方法返回的是 == 的判断。
Object类的公用方法

clone()、hashCode()、equals()、notify()、notifyAll()、wait()、getClass()、toString()、finalize()

Java的4种引用及其场景
引用类型 使用场景
强引用 使用普遍的引用;内存空间不足时,一般垃圾回收器绝不会回收它
软引用 可用来实现内存敏感的高速缓存;内存空间不足时,就会回收这些对象的内存
弱引用 具有弱引用的对象,不管当前内存空间是否足够都会回收它的内存
虚引用 虚引用并不会决定对象的生命周期。如果一个对象持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收
String、StringBuffer、StringBuilder的区别
类型 属性 是否可变 线程是否安全 适用场景
String 字符串常量(final修饰,不可继承) String对象一旦创建之后该对象不可更改
String str=“abc”;
str=str+“de”;
JVM又创建了一个新的名为str的对象,然后把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉
线程安全 适用于少量的字符串操作的情况
StringBuffer 字符串变量 对象可变 线程安全 适用多线程下在字符缓冲区进行大量操作的情况
StringBuilder 字符串变量 对象可变 线程不安全 适用于单线程下在字符缓冲区进行大量操作的情况
hashcode的总结
什么是HashCode
  • HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址的
  • 如果两个对象equals相等,那么这两个对象的HashCode一定也相同
  • 如果对象的equals方法被重写,那么对象的HashCode方法也尽量重写
  • 如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置
hashcode的作用

Java中的hashcode方法就是根据一定的规则将与对象相关的信息(比如:对象的存储地址、对象的字段等)映射成一个值(散列值),作用是降低equals的调用,实现存放的值不会重复

Note:重写 equals 必须重写 hashcode 方法,equals 相等,hashcode 也必须相等。
一般对于存放到 Set 集合或者 Map 中键值对的元素,需要按需要重写 hashcode 和 equals 方法,以保证唯一性。
例如:HashSet存放多个对象,重写 equals 和 hashcode

  • 对象相等,hashcode一定相同
  • 对象不相等,hashcode可能相同
  • hashcode相同的对象,不一定相等
  • hashcode不相同的对象,一定不相等
为什么重载hashcode方法
  • 重载时机:当类需要放在HashTable、HashMap、HashSet等hash结构的集合时需要重载hashcode。
  • 为什么重载:好比HashMap是一个大内存块,内部有很多小内存块,小内存块里面是一系列的对象,可以利用hashcode来查找小内存块hashcode%size,所以当equals相等时,hashcode必须相等,而且如果是Object对象,必须重载equals和hashcode方法。
ArrayList、LinkedList、Vector的区别
类型 线程是否安全 数据存储结构 适用场景 可否扩容 所需内存 区别原因
ArrayList 线程不安全 数组 适合查询 可自动扩容50% 少(存储每个索引的位置是实际的数据) 基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。获取数据的时间复杂度是O(1)。
但是要插入、删除数据却是开销很大的,因为这需要重排数组中的所有数据,还需要更新索引(除了插入、删除数组的尾部)时间复杂度是O(n)
LinkedList 线程不安全 链表 适合插入、删除 没有扩容的机制 多(每个节点中存储的是实际的数据和前后节点的位置) 插入、删除更快的。不像ArrayList一样需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,插入或删除的时间复杂度仅为O(1)。
Vector 线程安全 数组 适合查询 可自动扩容100% 少(存储每个索引的位置是实际的数据)
数组、链表在内存的存储
  • 数组:ArrayList — 静态分配内存,内存连续;数组元素在栈区
  • 链表:LinkedList — 手持下一个元素的地址,动态分配内存,内存不连续,链表元素在堆区
HashMap、HashTable、LinkedHashMap、TreeMap、ConcurrentHashMap的区别
类型 是否有序 是否可存null 是否线程安全 是否同步
HashMap 无序 允许存null 非线程安全 不同步
HashTable 有序 不允许存null 线程安全 同步(写入慢)
LinkedHashMap 有序(遍历比HashMap慢) 允许存null 非线程安全 不同步
TreeMap 有序 不允许存null 线程安全 同步
ConcurrentHashMap 有序 不允许存null 线程安全,适用于高并发 同步
HashMap的底层实现
  • HashMap的get(key)方法:获取key的hash值,计算 hash&(n-1) 得到在链表数组中的位置 first=tab[hash&(n-1)],先判断first的key是否参数key值相等,不等就遍历后面的链表,找到的key值返回对应的value值。

    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }
    
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }
    
  • HashMap的put(key)方法:判断键值对数组tab[]是否为空或null,否者以默认大小resize();根据键值key计算hash值得到插入的数组索引 i,如果tab[i]==null,直接新建节点添加,否则判断当前数组中处理hash冲突的方式为链表或红黑树(check第一个节点类型即可),分别处理。

    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
    
    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;
    }
    
  • 构造hash表:如果不指明初始大小,默认大小为16(即Node数组大小16),如果Node[]数组中的元素达到(填充比*Node.length)重新调整HashMap大小,变为原来的2倍大小,此过程非常耗时。

HashTable、ConcurrentHashMap的区别
  • HashTable:性能弱、迭代器一致性:强一致性(锁住整个map)
  • ConcurrentHashMap:性能强、迭代器一致性:弱一致性(锁住操作功能块,提升性能)
ConcurrentHashMap的并发度

ConcurrentHashMap的并发度:是segment的大小,默认为16;意味着最多同时可以有16条线程操作ConcurrentHashMap。

try{}catch{}finally{},try里有return,finally{}是否执行
  • 任何执行try或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。
  • 如果finally中有return语句,那么程序就执行finally中的return返回,所以finally中的return是一定会被当做返回值返回,此时的返回值不是try或catch中保存的返回值;编译器把finally中的return实现为一个warning。
Excption、Error包结构
  • Excption、Error都是Throwable的子类
  • Exception:指出了合理的应用程序想要捕获的条件。
  • Error:用于指示合理的用应程序不应该试图捕获的严重问题,大多数这样的错误都是异常条件。
OOM、SOF的发生的场景
  • OutOfMemoryError:Java Heap溢出、虚拟机栈和本地方法栈溢出、运行时常量池溢出、方法区溢出。
  • StackOverflowError:当程序递归太深而发生堆栈溢出时,抛出该错误。
IO、NIO的区别
IO NIO
面向流 面向块(缓冲区 Buffer)
阻塞 非阻塞
选择器(Selector)
管道(Channel)
少连接,大数据可用IO 多连接,少数据可以用NIO

猜你喜欢

转载自blog.csdn.net/zx711166/article/details/84846718