Java知识点(一)基础

一、Java中的作用域有哪些?

成员变量的4种作用域对比

作用域与可见性 当前类 同一package 子类 其他package
private × × ×
default × ×
protected ×
public

二、ArrayList和Vector的区别

  1. Vector的方法都是同步的,是线程安全的。而ArrayList的方法是线程不安全的,不是同步的。由于线程的同步必然要影响性能,因此,ArrayList一般多用于单线程环境下,而Vector一般多用于多线程环境下。
    以add方法为例,源码如下
    ArrayList add 方法源码
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

Vector add方法源码

    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }
  1. 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小。ArrayList、Vector默认容量都是10。如果预先能了解到有多少数据,应该给ArrayList或Vector一个初始值,以减少集合自动扩容的次数,提高程序性能。
//指定集合初始值
ArrayList<String> list = new ArrayList<>(100);

三、HashMap、HashTable、ConcurrentHashMap的原理与区别

HashTable

  • 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
  • 初始size为11,扩容:newsize = olesize*2+1
  • 计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

HashMap

  • 底层数组+链表实现,可以存储null键和null值,线程不安全
  • 初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
  • 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
  • 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
  • 计算index方法:index = hash & (tab.length – 1)

ConcurrentHashMap

  • 底层采用分段的数组+链表实现,线程安全
  • 通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍
  • HashTable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术

HashTable和HashMap都实现了Map接口,但是Hashtable的实现是基于Dictionary抽象类的。Java5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好

四、Java集合框架图

黄色的代表接口,绿色的是抽象类,蓝色的具体类


Collection
Map

五、Java的八种基本数据类型

Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
1. 四种整数类型(byte、short、int、long)

  • byte:8 位,用于表示最小数据单位,如文件中数据,-128~127
  • short:16 位,很少用,-32768 ~ 32767
  • int:32 位、最常用,-231-1~231 (21 亿)
  • long:64 位、次常用

注意事项: int i=5; // 5 叫直接量(或字面量),即 直接写出的常数。 整数字面量默认都为 int 类型,所以在定义的 long 型数据后面加 L或 l。 小于 32 位数的变量,都按 int 结果计算。

2. 两种浮点数类型(float、double)

  • float:32 位,后缀 F 或 f,1 位符号位,8 位指数,23 位有效尾数
  • double:64 位,最常用,后缀 D 或 d,1 位符号位,11 位指数,52 位有效尾数

注意事项:浮点数字面量默认都为 double 类型,所以在定义的 float 型数据后面加F 或 f;double 类型可不写后缀,但在小数计算中一定要写 D 或 X.X 。浮点数是不精确的,不能对浮点数进行精确比较。

3. 一种字符类型(char)

  • char:16 位,是整数类型,用单引号括起来的 1 个字符(可以是一个中文字符),使用 Unicode 码代表字符,0~2^16-1(65535)

注意事项:不能为 0个字符。
转义字符:\n 换行 \r 回车
两字符 char 中间用“+”连接,内部先把字符转成 int 类型,再进行加法运算,char 本质就是个数!二进制的,显示的时候,经过“处理”显示为字符。

4. 一种布尔类型(boolean)
true 真 和 false 假

类型转换:char--> 自动转换:byte-->short-->int-->long-->float-->double
强制转换:①会损失精度,产生误差,小数点以后的数字全部舍弃。②容易超过取值范围

记忆:8位:Byte(字节型) 16位:short(短整型)、char(字符型) 32位:int(整型)、float(单精度型/浮点型) 64位:long(长整型)、double(双精度型) 最后一个:boolean(布尔类型

代码测试

 long n = 4;  // 编译通过,可以不加L或l,4为int可以用long来装
 long n2 = 4L; // n == n2  为true
        
 float f = 2.4; // 编译不通过,2.4要加f 因为浮点数字面量默认都为double类型
 float f2 = 2.4f; // 编译通过
     
 double d = 2.4; // d == f2  为false  因为一个为float一个为double
 double d2 = 2.4f; // 编译通过,2.4f为float 可以用double来装
        
 // f2 == d2 为true
   char a ='a';
   char b = 'b';
        
   char c = '陈'; // 编译通过
   char d = 'a'+'b'; // A
        
   char e = a+b; // 编译不通过
   char f = 'ab'; // 编译不通过
   char g = ''; // 编译不通过

六、Java中异常处理机制

1. Java异常
异常是什么?不正常的事件。运行程序时,它没有按照我们的预期执行,也就是不正常的运作,就叫异常。Java标准库内建了一些通用的异常。Throwable派生Error、Exception。Error类及其子类代表的是JVM本身的错误,并非程序的问题,不能由程序员通过代码进行处理。Exception及其子类代表的是在程序运行过程中产生的不期望发生的异常事件,可以被Java异常处理机制进行处理,是异常处理的核心。

JDK8的异常类导图

2. 异常处理语句及语法
在写代码处理异常的时候,有两种不同的处理方式:

  • 1.使用try..catch..finally处理
  • 2.使用throws声明抛给函数调用者去处理

try...catch..finally语句块

try{
     //1.存放可能发生异常的代码。
     //2.如果没有发生异常,执行finally块代码(如果有finally块)并往下执行代码,否则,直接尝试去匹配catch块。
 
}catch(IOException e1){
    //每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。
    //catch后面的括号定义了异常类型和异常参数(局部的)。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
    //在catch块中可以使用这个块的异常参数来获取异常的相关信息(getMessage()、printStackTrace()、getCause())。
}catch(Exception e2){
    //...
}finally{
    //finally块可要可不要。
   //一个try至少要有一个catch块,否则, 至少要有1个finally块。但是finally不是用来处理异常的,finally不会捕获异常。
  //finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。 
}

需要注意的是:
1.try块发生异常,那么try块中发生异常的那一行以下的代码都不会执行。
2.无论异常发生与否,异常是否有catch匹配处理,finally块都会执行。
3.如果catch中有return,先将return值暂存起来,再执行finally,最后再return

public class Client {
    public static void main(String[] args) {
        System.out.println("result:"+fun());
    }
    
    static int fun() {
        int a = 1;
        try {
            a =2;
            int b = 1/0;
            System.out.println(" a = "+a); //异常后面的代码不会执行
            return a; //异常后面的代码不会执行
        }catch(Exception e){
            a =3;
            System.out.println("catch a = "+a);
            return a; //将a的值暂存起来,return 的时候返回出去, 再执行finally,最后执行return
        }finally {
            a = 4;
            System.out.println("finally a = "+a);
        }
    }
}

运行结果:

catch a = 3
finally a = 4
result:3
public class Client {
    public static void main(String[] args) {
        System.out.println("result:"+fun2());
    }
    
    static int fun2() {
        int a = 1;
        try {
            a =2;
            System.out.println(" a = "+a); 
            return a;//将a的值暂存起来,return 的时候返回出去, 再执行finally,最后执行return
        }catch(Exception e){
             //因为没有异常,所以下面代码都不会执行
            a =3;
            System.out.println("catch a = "+a);
            return a; 
        }finally {
            a = 4;
            System.out.println("finally a = "+a);
        }
    }
}

运行结果:

 a = 2
finally a = 4
result:2

3. 非检查异常 & 检查异常
非检查异常(unchecked exception):
包括Error和RuntimeException以及他们的子类。java编译器在编译时,不会提示和发现这样的异常,不要求在程序预处理这些异常,但是如果有异常产生,则异常将由JVM进行处理。当然如果你觉得可能会有异常就可以使用try..catch处理或throws抛出。

检查异常(checked exception):
包括除了Error和RuntimeException的其他异常。java编译器强制要求程序员预处理,不然编译器就会报错不让你通过,如FileNotFoundException。

非检查异常 & 检查异常

4. Java自定义异常,应该继承Exception还是Runtime Exception
RuntimeException属于Exception的子类
Exception是在编译时候如果有异常就可以检查出来,比较严谨!
RuntimeException比较特殊,他及其子类对象,属于运行时候检查的异常,如果语法没有错误他不会在编译时候报异常的,只有运行的时候才会抛出异常!

至于继承谁,得看类具体的功能,其实这两点已经说的很明确了,如果继承了Exception要么抛出去给上级调用者,要么调用异常代码的时候进行捕捉,有相对应的处理方式。如果继承的是RuntimeException,可以不用抛,也可以不用捕捉但是问题是在运行的过程中才会展现出来,一但出错,后面程序将无法继续运行。
我在使用Spring Boot的时候,一般用的是RuntimeException,因为不用自己去处理异常或向上抛出异常,而是统一拦截交给全局异常处理。

七、String,StringBuilder,StringBuffer三者的区别

  • String : 字符串常量,不可变,非线程安全;适合声明一个字符串常量,不适合做连接字符串操作。
  • StringBuilder:字符串变量,可变,非线程安全;适用于单线程下在字符缓冲区进行大量操作的情况。
  • StringBuffer:字符串变量,可变,线程安全;适用多线程下在字符缓冲区进行大量操作的情况。

八、Class.forName的作用以及为什么要用它

我们查看Class.forName源码,可看到注释为:
Returns the {@code Class} object associated with the class or
* interface with the given string name
大概意思是:使用Class类中静态forName()方法获得与字符串对应的Class对象

Class.forName作用为:给定一个字符串变量,它代表一个类的包名和类名,通过Class.forName实例化它

//方式一
A a = (A)Class.forName("pacage.A").newInstance(); 
//方式二
A a = new A(); 

方式一和方式二效果是一样的。

在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:
1、这个类已经加载;
2、这个类已经连接了。

而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。

现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class.forName方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用Class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。Java中工厂模式经常使用newInstance()方法来创建对象

new关键字和newInstance()方法的区别:
newInstance: 弱类型,低效率,只能调用无参构造。
new:强类型,相对高效,能调用任何public构造。

九、什么是序列化?序列化的作用,应用场景

序列化:所谓java对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象,Java通过实现Serializable接口来实现序列化。
序列化作用:序列化将对象流化,然后进行传输和存储。再通过反序列化将流重组成对象。
应用场景:对象序列化后存在在文件中;对象经过分布式系统进行网络传输;

十、Collection和Collections有什么区别

  • Collection是集合类的上级接口,继承与他的接口主要有Set 和List
  • Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作

十一、int和Integer有什么区别

int是java提供的8种原始数据类型之一,Java为每个原始类型提供了封装类,Integer是java为int提供的封装类。

int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况。要想表达出没有参加考试和考试成绩为0的区别,则只能使用Integer。

在Hibernate中,如果将OID定义为Integer类型,那么Hibernate就可以根据其值是否为null而判断一个对象是否是临时的,如果将OID定义为了int类型,还需要在hbm映射文件中设置其unsaved-value属性为0。

另外,Integer提供了多个与整数相关的操作方法,例如,将一个字符串转换成整数,Integer中还定义了表示整数的最大值和最小值的常量。

十二、是否可以从一个static方法内部发出对非static方法的调用

不可以。因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用。也就是说,当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用,那个非static方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个static方法内部发出对非static方法的调用。

十三、创建对象的几种方式

new、反射、反序列化、Clone

十四、变量是存储信息的容器

实例

    int x=5;
    int y=6;
    int z=x+y;

类似代数

     x=5
     y=6
     z=x+y

在代数中我们使用字母(比如 x)来保存值(比如 5),从上面的表达式 z=x+y,我们能够计算出 z 的值是 11,在Java 中,这三个字母被称为变量。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 整理来自互联网 1,JDK:Java Development Kit,java的开发和运行环境,java的开发工具...
    Ncompass阅读 1,559评论 0 6
  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 2,709评论 0 11
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,427评论 0 4
  • 一:java概述: 1,JDK:Java Development Kit,java的开发和运行环境,java的开发...
    慕容小伟阅读 1,848评论 0 10
  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 3,751评论 0 11