java基础

420 阅读16分钟

jre和jdk区别

jdk(java development kit) 开发工具

  • 基本类库
  • javac
  • javap
  • javadoc
  • 运行环境 jre(java runtimr environment):单单运行一个java程序,只安装jre即可

==与equals的区别

  1. ==:
  • 基本类型(8种):short int long float double byte boolen char 比较值相等。
  • 引用类型:比较的是地址,看引用的对象是不是同一个
  1. equals:
  • 重写object的equals方法:自己定义比较规则。我们常见的对象都已经重写了equals方法
  • 不重写object的equals方法:就是比较引用地址是否相同,相当与==

解释: object下面的一个方法。 如果没重写这个方法,那么比较的是地址。

如果重写了这个方法,比如string这个类型的对象重写了这个方法,不再比较地址了。

string a="abf"; string b=new string("abf"); a.equals(b); //true

hashcode和equals相同吗

final有什么作用

final作用在类、方法、变量上

  • 类:不能被继承
  • 方法:不能被重写
  • 变量:基本类型的话:值不能变;引用类型:地址不可变,引用的对象内部的值可以变

操作字符串有那些类?他们之间的区别

  • String:值不可变
  • StringBuilder:值可变,不加锁,不安全,速度快
  • StringBuffer:值可变,加锁synchronized,线程安全

string a="qwe";
a="wer";
//stringPool["que","wer"];
//方法区里面有一个字符串常量池,“que”放到常量池里面,a直接指向“quw”,a再指向“wer”,如果常量池有“wer”,就指向,没有的话就创建哥“wer”,然后a指向“wer”

StringBuilder sb=new StringBuilder();
StringBuffer sb2=new StringBuffer();
//StringBuilder和StringBuffer都继承AbstractStringBuilder类,他们两个值改变,其实是改变里面都数组都值,比如append方法,源码如下

java种的math.round(-1,5)等于多少

答案:-1

  • round:返回四舍五入,负.5小数返回较大整数,如-1.5返回-1。
  • ceil:返回小数所在两整数间的较大值,如-1.5返回-1。
  • tail:返回小数所在两整数间的较小值,如-1.5返回-2。

java种的math.round(1,5)等于多少 --2

hashmap和hashtable的区别

都是map的实现类,都是存储键值对的<key,value>
  |_hashMap:线程不安全,速度快。允许放入空值,hashmap.put(null.null)。
  |_hashtable:加锁,线程安全,速度相对慢。不允许放空值。

简单聊一聊hashmap

  • 存储结构:entry的数组,entry<key,value>,entry本身也是一种链表结构,长度大于等于8,变成红黑树。
  • 存储逻辑:根据计算hash值放到对应位置。
  • 扩容方案:达到域值的话,进行扩容,自身容量扩大一倍,成倍增长

Vector和ArrayList的区别

都实现了List的接口。

  • Vector:加锁,线程安全。扩容:2倍增长。
  • ArrayList:线程不安全。扩容:1.5倍增长

为什么Vector用的少: 1.线程安全,牺牲了速度 2.扩容大,需要连续存储空间比较大 3.因为内部是一个数组,所以插入、删除比较慢。可以用LinkedList来实现快速插入删除操作

java虚拟机之JVM内存区域

java虚拟机之Java类加载机制

类的生命周期、类的加载过程

类加载器

java虚拟机之垃圾回收机制

1.什么是垃圾回收

对资源有效利用。资源:java运行内存,垃圾:不再被使用但是还残留在内存中对对象。

2.java内存很大,残留在哪块内存里面呢?

  • 线程私有:虚拟机栈、程序计数器、本地方法栈(随着线程创建而被开辟出来,线程一旦结束,这些内存会被释放。不需要垃圾回收)
  • 线程共有:堆、方法区(99%的对象实例都是被存放在堆里面的)

3.什么样子的对象被视为垃圾?

1.引用计数器算法

堆中每个对象都有一个计数器,当对象被被其他对象引用时,计数器+1,当引用失效时-1,如果引用计数器为0时,该对象就会被回收。 缺点:当两个对象互相引用,而他们两个没有被用到时,这两个对象不会被回收。

2.可达性分析算法

以GCRoot作为起点开始搜索,在引用链上的对象不可被回收,不在引用链上的对象可以被回收。

哪些可以作为GCRoot对象呢?
  • 活的线程
  • 方法区中的静态变量和常量引用的对象
  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 本地方法栈中(即一般说的native方法)引用的对象

垃圾回收算法

  • 标记-清除:产生内存碎片 描述:把可回收的内存进行标记,然后直接回收
  • 复制:又一半空间被浪费 描述:把内存分成一半一半,把存活的内存全部放到另一半上,这样原先的内存剩下的都是可回收的,然后进行回收。
  • 标准-整理:速度比较慢 描述:把可回收和不可回收的标记,然后将内存移动整理成一大块整体连续的内存,把另一边可回收的内存回收。
  • 分代回收算法:
    1. 新生代(存活时间短的对象):复制算法
    2. 老生代(存活时间长的对象):标记清除算法、标记整理算法

线程和进程区别

  • 进程:是系统运行分配和管理资源的单位
  • 线程:进程的一个执行单位,是进程内调度的实体、是CPU调度和分配的基本单位,是比进程更小的独立运动的基本单位。线程也被称为轻量级进程,线程是执行程序的最小的单位。

一个程序至少一个进程,一个进程至少一个线程。

进程有自己独立地址空间,每启动一个进程,系统就会为他分配地址空间,建立数据表来维护代码段、堆栈段、数据段,这种操作非常昂贵。 而线程共享进程中的数据的,使用相同的地址空间,因此cpu切换一个线程的花费远比进程要小很多,同时创建一个线程的开销比进程要小很多。

多线程之线程的三种创建方式

  1. 重写Thread的run方法
  2. 实现runnable
  3. 实现callable

runnable和callable

callable是runnable的延伸,callable接口可以返回结果值,需要在定义的时候执行类型

线程的六种状态

  • new :初始化态/新建状态。线程创建且没有执行start方法时的状态。
Thread a= new Thread();
  • runnale:可运行状态。
      1. ready:可运行状态/准备态,线程已经启动,但是等待相应的资源(比如IO或者时间片切换)才能开始执行
      1. running:运行态,线程获取了CPU,执行程序代码。
a.start();
  • blocked:阻塞态。 运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中
  • waiting 运行(running)的线程执行wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
  • timed_waiting:超时等待。等待固定的时间,比如wait(3000)
  • terminated:结束态。线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

多线程之 wait 、sleep、yield的区别

  • sleep:

    • 暂停当前线程执行,但是不释放锁
    • sleep是在thread中的一个静态方法,thread.sleep();
    • sleep可以在任何场景下使用
    • 只有睡够时间才能醒
  • wait

  • 暂停当前线程执行,但是释放锁
  • wait是Object的对象,object.wait
  • wait只能在同步代码块中使用
  • wait可以随时唤醒(notify、notifyAll)
  • yield
  • 给相同优先级的线程让出 cpu 资源,让步的线程还有可能被线程调度程序再次选中。如果没有相同优先级的线程,那么它还是会得到执行。

线程同步的方法

线程同步概念:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多,临界区对象就是其中一种。

用synchronized关键字。因为java为每一个对象都设置了内置锁,当使用synchronized关键字修饰方法时,内置锁就会保护这个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

  • 非静态方法:锁住的是当前对象
  • 静态方法,此时如果调用该静态方法,将会锁住整个类。
  • 代码块:同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。
//锁代码块的几种情况
 public void test(){
    //传this,是对象锁
        synchronized (this) {
            // TODO
        }
  }
    
    public void method2(){     
    //传类,类锁。作用:这个类的所有对象
        synchronized (ObjectLock.class) {
            try {
                System.out.println("do method2..");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
     private Object lock = new Object();
    public void method3(){      //任何对象锁
        synchronized (lock) {
            try {
                System.out.println("do method3..");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

多线程之java线程池

多线程之生产者-消费者模型

生产者生产数据,消费者消费数据。生产者和消费者数据共享。内存满的时候,需要生产者需要等待,内存中没有数据时候,消费者需要等待。

volatile关键字

原子性&&可见性

可见性:当一个线程修改了线程共享变量的值,其它线程能够立即得知这个修改。用volatile 原子性:一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行。用锁。

java中实现多态的机制是什么

靠的是父类的引用指向子类的对象(多态性)。调用的方法是内存中正在运行的那个对象的方法,若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法。

异常分为哪些种类

编译时异常、运行时异常

java异常处理机制

finally里面有异常

finally return

1.public int getNum(){
2. 	try {
3. 		int a = 1/0;
4.		return 1;
5.		}catch (Exception e){
6.			return 2;
7.		}finally{
8.			return 3; 
9. 		}

代码在走到第 3 行的时候遇到了一个 MathException,这时第四行的代码就不会执行了,代码直接跳转到 catch 语句中,走到第 6 行的时候,异常机制有这么一个原则如果在 catch 中遇到了 return 或者异常等能使该函数终止的话那么有 finally 就必须先执行完 finally 代码块里面的代码然后再返回值。因此代码又跳到第 8 行,可惜第 8 行是一个 return 语句,那么这个时候方法就结束了,因此第 6 行的返回结果就无法被真正返回。如果 finally 仅仅是处理了一个释放资源的操作,因此上面返回值是3。

finally和return

blog.csdn.net/weixin_4100…

如何将java对象序列化到文件里

泛型原理,并举例

泛型中extends和super区别

抽象类和接口的区别

抽象类 :

  1. 抽象类不可以被实例化,实例化由子类去完成
  2. 抽象方法必须由子类重写(非抽象子类,抽象子类可不重写)
  3. 只要有抽象方法,就是抽象类
  4. 可以实现具体的方法,也可以不实现
  5. abstract 不能与private、static、final或native并列修饰同一个方法
  6. 可以和普通方法一样有成员变量,常量等。

接口:

  1. interface 是 public 的
  2. 接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误)
  3. 接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。java 8 以后可以加 default 关键字实现方法
  4. 不能使用new操作符实例化一个接口,但可以声明一个接口变量,该变量必须引用(refer to)一个实现该接口的类的对象。
  5. 可以使用 instanceof 检查一个对象是否实现了某个特定的接口。例如:if(anObject instanceof Comparable){}
  6. 在实现多接口的时候一定要避免方法名的重复

区别:

  • 抽象类不能被多继承,接口可以被多实现。也可以被多继承。
  • 抽象类是对类抽象,而接口是对行为的抽象
  • 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型; 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法。

string转乘integer的方式和原理

哈希冲突

容器(hashmap、hashset、linkedList、hashset)

java反射的理解

什么是线程池,如何使用,为什么使用

java引用类型有哪些

blog.csdn.net/baidu_22254… Java中4种引用的级别和强度由高到低依次为:强引用 -> 软引用 -> 弱引用 -> 虚引用 ①强引用(StrongReference) ②软引用(SoftRefernce) ③弱引用(WeakReference) ④虚引用(PhantomReference)

  • 强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。
  • 如果一个对象只具有软引用,则内存空间充足时,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
  • 软引用可以和一个引用队列(ReferenceQueue)联合使用。如果软引用所引用对象被垃圾回收,JAVA虚拟机就会把这个软引用加入到与之关联的引用队列中。
  • 弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
  • 同样,弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。可见WeakReference对象的生命周期基本由垃圾回收器决定,一旦垃圾回收线程发现了弱引用对象,在下一次GC过程中就会对其进行回收
  • 虚引用顾名思义,就是形同虚设。与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。

重载和重写的区别

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。

重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重载对返回类型没有特殊的要求,不能根据返回类型进行区分。

重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。

设计模式

单例模式

饿汉式 (可用)

就是在类定义的时候就实例化了(因为饿,主观能动性强 - . -)。

public class Singleton {
    private final static Singleton INSTANCE = new Singleton();
    
    private Singleton(){}
    
    public static Singleton getInstance(){
        return INSTANCE;
    }
}

普通的懒汉式 (线程不安全,不可用)

这种写法有个致命的问题,就是多线程的安全问题。假设对象还没被实例化,然后有两个线程同时访问,那么就可能出现多次实例化的结果,所以这种写法不可采用。

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

}

同步方法的懒汉式 (可用)

这种写法是对getInstance()加了锁的处理,保证了同一时刻只能有一个线程访问并获得实例,但是缺点也很明显,因为synchronized是修饰整个方法,每个线程访问都要进行同步,而其实这个方法只执行一次实例化代码就够了,每次都同步方法显然效率低下,为了改进这种写法,就有了下面的双重检查懒汉式。

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

双重检查懒汉式 (可用,推荐)

这种写法用了两个if判断,也就是Double-Check,并且同步的不是方法,而是代码块,效率较高,是对第三种写法的改进。为什么要做两次判断呢?这是为了线程安全考虑,还是那个场景,对象还没实例化,两个线程A和B同时访问静态方法并同时运行到第一个if判断语句,这时线程A先进入同步代码块中实例化对象,结束之后线程B也进入同步代码块,如果没有第二个if判断语句,那么线程B也同样会执行实例化对象的操作了。

public class Singleton {

    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

}

静态内部类 (可用,推荐)

因为类的静态属性只会在第一次加载类的时候初始化,也就保证了SingletonInstance中的对象只会被实例化一次,并且这个过程也是线程安全的。

public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

观察者模式

实现:

适配器模式

装饰器模式

实现:

代理模式