JDk和JRE的区别
JDK : JDK是整个java的核心, 包括了java运行环境JRE, 一堆java工具和java基础的类库. 通过JDK开发人员将源码文件编译成字节文件 源码java 字节class
JRE: JRE是java运行环境, 不含开发环境,即便没有编译器和调试器, 将class文件加载到内存准备运行
讲一讲Java内存的堆(heap)、栈(stack)和方法区(method)
栈:调用方法将在栈中开辟内存,称为入栈(压栈)。
栈内存存放基本类型值和引用数据类型的地址。
栈内存中的数据,没有默认初始化值,需要手动设置。
方法调用完成,栈内存立即释放,称为出栈(弹栈)
堆:用于存放使用new创建的对象或数组。
所有的对象都有内存地址值。
数据都有默认初始化值。
堆内存中的对象不再被指向时,JVM启动垃圾回收机制,自动清除。
方法区:与Java堆一样,是各个线程共享的内存区域。
存储已被Java虚拟机加载的类信息、常量、静态变量、以及编译器编译后的代码等。
GC是什么? 为什么要有GC?
GC是垃圾收集的意思。
是指JVM用于释放那些不再使用的对象所占用的内存。垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。Java有了GC,就不需要程序员去人工释放内存空间。
说说&和&&的区别
& 位运算,求2个二进制数的与。也可以进行逻辑运算,表达式左边为false,表达式右边继续执行。
&& 逻辑运算符,表达式左边为false,整个表达式结果为false,因此表达式右边不执行。此现象称为逻辑短路。
super与this的区别
1.this表示对象本身,用来调用当前类里的属性、方法,也可以调用从父类继承而来的未被重写、非私有的方法;
super表示当前对象类的父类对象部分,用来调用父类里的属性、方法;
2.this和super用来调用构造器方法
不同点:super()从子类中调用父类的构造方法,this()在同一类内调用其它构造方法。
相同点:super()和this()都必须在构造函数的第一行进行调用,否则就是错误的
"=="和equals方法究竟有什么区别?
比较的是值
== 如果比较的是基本数据类型,比较的则是变量值
== 如果比较的为引用数据类型,比较的则是地址值
equals比较的是引用数据类型
如果没有重写hashCode和equals方法,比较的是地址值。因为Object的equals方法中使用是。
如果重写hashCode和equals方法,则比较的重写后的规则。
例如:两个String字符串比较时:比较的是内容。因为String底层重写了equals方法进行内容的比较。
static和final关键字
static关键字为静态的
1.用来修饰成员变量,静态变量所有对象共享;
2.用来修饰成员方法,可通过“类名.方法名”的方式调用,常用于工具类;
3.静态代码块,在类被加载的时候就会被执行的代码块;
final关键字
1.用来修饰数据,包括成员变量和局部变量,该变量只能被赋值一次且它的值无法被改变。对于成员变量来讲,必须在声明时或者构造方法中对它赋值;
2.修饰方法,表示该方法无法被重写;
3.修饰类,表示该类无法被继承。
List, Set, Map的区别
1、List中的元素,有序、可重复、可为空;
2、Set中的元素,无序、不重复、只有一个空元素;
3、Map中的元素,无序、键不重,值可重、可一个空键、多个空
ArrayList和LinkedList有什么区别?
1, ArrayList的底层是动态数组;LinkedList的底层是双向链表
2, ArrayList默认初始大小为10,默认扩容大小为1.5倍;LinkedList将元素添加到链表的末尾,无须扩容
3, ArrayList查询快, 增删慢, LinkedList增删除快, 查询慢
如何对list集合中的数据进行去重
1.借助set集合
2.利用List的contains方法循环遍历
数组和链表分别适用于什么场景,为什么
数组:查询多,增删少; 数组的特性
链表:查询少,增删多; 链表的特性
HashMap的底层结构
HashMap底层数据结构为数组+链表;在JDK1.8中当链表的长度超过8时,链表会转换为红黑树;
HashMap怎么将数据存在有限的数组中
(HashMap如何存储数据?)
1、如果数组还没有初始化(数组长度是0),则先初始化,默认16
2、通过hash方法计算key的hash值,hash值对数组长度进行取余操作,进而计算得到应该放置到数组的位置
3、如果该位置为空,则直接放置此处
4、如果该位置不为空,而且元素是红黑树,则插入到其中
5、如果是链表,则遍历链表,如果找到相等的元素则替换,否则插入到链表尾部
6、如果链表的长度大于或等于8,则将链表转成红黑树
HashMap在JDK1.8与JDK1.7中有什么不同
1、1.8中引入了红黑树,而1.7中没有
2、1.8中元素是插在链表的尾部,而1.7中新元素是插在链表的头部
3、扩容的时候,1.8中不会出现死循环,而1.7中容易出现死循环
HashMap和HashTable的区别
1)HashMap是非线程安全的,HashTable是线程安全的,内部的方法基本都经过synchronized修饰。
(2)因为同步、哈希性能等原因,HashMap的性能优于HashTable
(3) HashMap允许有null值的存在,在HashTable不允许有null值
(4)HashMap默认初始化数组的大小为16,HashTable为11。前者扩容时乘2,使用位运算取得哈希,效率高于取模。而后者为乘2加1,都是素数和奇数,这样取模哈希结果更均匀。
TCP和UDP的区别
1、TCP(面向连接如打电话要先拨号建立连接),建立TCP连接需经过三次握手,释放TCP连接需经过四次挥手;UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP对系统资源要求较多,UDP对系统资源要求较少。
在java中,对象什么时候可以被垃圾回收?
一般情况下java中对象可被回收的前提是:该对象不再被引用。然后垃圾回收器在回收的时候便会把这个对象清理掉
垃圾回收机制的算法:(扩展)
1 引用计数算法:
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器都为0的对象就是不再被使用的,垃圾收集器将回收该对象使用的内存。
2 根搜索算法:
通过一系列的名为“GC Root”的对象作为起点,从这些节点向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Root没有任何引用链相连时,则该对象不可达,该对象是不可使用的,垃圾收集器将回收其所占的内存。
java中会存在内存泄漏吗,请简单描述。
会存在,
内存泄漏是指程序分配的内存未释放或无法释放的现象。
java中内存泄露的发生场景:全局的集合变量、不正确的单例模式的使用
Java中内存泄漏产生的原因可能有哪些?
递归的时候会引起栈内存溢出
1、静态集合类引起内存泄漏;
2、当集合里面的对象属性被修改后,再调用remove()方法时不起作用;
3、监听器
4、各种连接
5、内部类和外部模块的引用
6、单例模式
具体说明请自行查看原文,链接:https://blog.csdn.net/c_royi/article/details/79527518
*面向对象的基本特征是什么/什么是面向对象/你是如何理解面向对象的
封装 有选择的隐藏和暴露一些数据和方法
继承 子类可以直接实现父类中的方法,有选择的扩展
多态 调用同一个方法展示出来不同的方式。
抽象 把共同的特性抽取到一个类中
讲一下你对OOP的理解
OOP(object oriented programming),即面向对象编程
面向对象具有四大特性,分别是
1.抽象
将一些事物的共性抽离出来归为一个类。
如对于动物,具有生命体征、活动能力等区别于其它事物的共同特征
2.封装
有选择地隐藏和暴露数据和方法
比如有U盘这个类,我希望隐藏内部组成和实现,只暴露USB接口以供使用
3.继承
子类可以直接使用父类的部分数据和方法,可以有选择的扩展
比如鸟是动物,但鸟扩展了飞行的能力。
4.多态
同一类的对象调用相同方法可以表现出不同的行为
比如动物实现了say()方法,猴子、马等动物重写了say()方法来表现不同的交流语言。
Java中实现多态的机制是什么?
Java中,靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
Overload和Override的区别?
方法重写(overriding):
1、也叫子类的方法覆盖父类的方法,要求返回值、方法名和参数都相同。
2、子类抛出的异常不能超过父类相应方法抛出的异常。(子类异常不能超出父类异常)
3、子类方法的的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)
方法重载(overloading):
重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,但是参数却不相同,方法体也不相同,最常见的重载的例子就是类的构造函数
构造器是否可被override
Constructor(构造器)不能被继承,所以不能被override(重写),但是可以被overloading(重载)。
抽象类和接口的区别
抽象类是什么
含有abstract修饰符的class即为抽象类。
特点:
字节高效流:BufferedOutputStream 、BufferedInputStream
字符高效流:BufferedWriter、BufferedReader
转换流: OutputStreamWriter、InputStreamReader
什么是Java序列化,如何实现Java序列化?
java的序列化:
把Java对象转换为二进制数据流的过程。
实现:
需要序列化的类实现Serializable接口
序列化和反序列化的含义
1.把内存中的对象保存到一个文件中或者数据库中;
2.网络上传送对象;
3.通过RMI传输对象;
好处:
1.描述数据的传输格式,这样可以方便自己组织数据传输格式,以至于避免一些麻烦及错误
2.如果是跨平台的序列化,则发送方序列化后,接收方可以用任何其支持的平台反序列化成相应的版本,比如 Java序列化后, 用.net、phython等反序列化
transient关键字对序列化有影响吗
有,transient表示瞬态的,被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
什么是线程?什么是多线程?
1)什么是线程:
在一个进程中,每个独立的功能都需要独立的去运行,这时又需要把当前这个进程划分成多个运行区域,每个独立的小区域(小单元)称为一个线程。
例如:360杀毒软件,同时既可以安全体检电脑又可以清理电脑中的垃圾。那么这里的安全体检是360杀毒软件中的一个线程,清理电脑中的垃圾也是一个线程。
2)什么是多线程:
一个进程如果只有一条执行任务,则称为单线程程序。
一个进程如果有多条执行任务,也就是说在一个进程中,同时开启多个线程,让多个线程同时去完成某些任务(功能)。则称为多线程程序。
实现多线程的方式?用哪个更好?
1.方式一:继承Thread,重写Thread类中的run方法;
2.方式二:实现Runnable接口,实现run方法;
3.方式二的方式更好,原因是:
①避免了Java单继承的局限性;
②把线程代码和任务的代码分离,解耦合(解除线程代码和任务的代码模块之间的依赖关系)。代码的扩展性非常好;
③方式二可以更方便、灵活的实现数据的共享
什么是线程安全问题
多线程环境中,且存在数据共享,一个线程访问的共享数据被其它线程修改了,那么就发生了线程安全问题;整个访问过程中,无一共享的数据被其他线程修改,就是线程安全的
如何解决线程安全问题
1.使用线程同步机制,使得在同一时间只能由一个线程修改共享数据;
2.消除共享数据:即多个线程数据不共享或者共享的数据不做修改。
使用局部变量,不使用成员变量。
如果使用成员变量,对成员变量不进行修改。
什么是线程同步?
当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态
启动一个线程是用run()还是start()? .
启动线程使用的是start()方法。
当用start()开始一个线程后,线程就进入就绪状态,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。当cpu分配给它时间时,才开始执行run()方法(如果有的话)。start()是方法,它调用run()方法.而run()方法是你必须重写的. run()方法中包含的是线程的主体
什么是死锁?死锁产生的原因有哪些?
1.什么是死锁
死锁是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待的现象
2.死锁产生的原因
①系统资源的竞争
通常系统中拥有的不可剥夺资源,其数量不足以满足多个进程运行的需要,使得进程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。
②进程推进顺序非法
进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如,并发进程 P1、P2分别保持了资源R1、R2,而进程P1申请资源R2,进程P2申请资源R1时,两者都 会因为所需资源被占用而阻塞
什么是线程同步?
当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态
启动一个线程是用run()还是start()? .
启动线程使用的是start()方法。
当用start()开始一个线程后,线程就进入就绪状态,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。当cpu分配给它时间时,才开始执行run()方法(如果有的话)。start()是方法,它调用run()方法.而run()方法是你必须重写的. run()方法中包含的是线程的主体
什么是死锁?死锁产生的原因有哪些?
1.什么是死锁
死锁是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待的现象
2.死锁产生的原因
①系统资源的竞争
通常系统中拥有的不可剥夺资源,其数量不足以满足多个进程运行的需要,使得进程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。
②进程推进顺序非法
进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如,并发进程 P1、P2分别保持了资源R1、R2,而进程P1申请资源R2,进程P2申请资源R1时,两者都 会因为所需资源被占用而阻塞
死锁产生的必要条件?如何解决死锁问题
死锁产生的条件
产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生。
①互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。
②请求与保持条件(Hold and wait):进程已获得了一些资源,但因请求其它资源被阻塞时,对已获得的资源保持不放。
③不可抢占条件(No pre-emption) :有些系统资源是不可抢占的,当某个进程已获得这种资源后,系统不能强行收回,只能由进程使用完时自己释放。
④循环等待条件(Circular wait):若干个进程形成环形链,每个都占用对方申请的下一个资源。
如何解决死锁问题?
死锁解决几种方式:
①加锁顺序(线程按照一定的顺序加锁,只有获得了从顺序上排在前面的锁之后,才能获取后面的锁)
②加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
③死锁检测 (判断系统是否处于死锁状态)
④死锁避免(指进程在每次申请资源时判断这些操作是否安全。例如银行家算法:在分配资源之前先看清楚,资源分配后是否会导致系统死锁。如果会死锁,则不分配,否则就分配。)
sleep()和wait()的区别
1.sleep()方法,属于Thread类的。;wait()方法,则是属于Object类的;
2.sleep方法不会释放锁,而wait方法会释放锁
3.wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
4.sleep需要接收时间参数,wait不需要接收时间参数;
5.sleep可以自然醒,wait必须等待别人唤醒;
notify和notifyAll
notify和notifyAll都可以唤醒处于等待的线程。
1.如果调用了线程 wait()方法,那么线程便会处于等待状态。
2.当调用notifyAll()方法后,将唤醒所有等待的线程
3.当调用notify()方法后,将随机唤醒一个等待线程
什么是锁机制?及其优缺点
有些业务逻辑在执行过程中要求对数据进行排他性的访问,于是需要通过一些机制保证在此过程中数据被锁住不会被外界修改,这就是所谓的锁机制。
优点:保证资源同步
缺点:有等待肯定会慢
乐观锁和悲观锁
悲观锁:总是假设最坏的情况。
每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。
传统的关系型数据库里边就用到了很多这种锁机制,比如读锁,写锁等,都是在做操作之前先上锁。
乐观锁
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。
乐观锁适用于写比较少的情况,即冲突真的很少发生,这样可以省去锁的开销,从而提高系统的吞吐量。
悲观锁使用于写比较频繁的情况,即经常产生冲突,上层引用会不断的进行重试,这样反倒降低了性能,所以使用锁比较合适。
反射的原理及应用
原理:反射在程序运行时,能够动态的操作类的成员。
1.反射前提:通过字节码获得Class对象
2.反射操作:通过Class对象对构造Constructor、字段Field、方法Method进行动态操作。
3.反射应用:框架底层都使用了反射
手写单例设计模式(懒汉式、饿汉式-基于双重检查锁)**
1.饿汉式单例设计模式:
public class Singleton {
//私有构造方法
private Singleton() {}
//单例对象
private volatile static Singleton instance = new Singleton();
//静态工厂方法
public static Singleton getInstance() {
return instance;
}
}
2.基于双重检查锁的懒汉式单例设计模式:
public class Singleton {
//私有构造方法
private Singleton() {}
//单例对象
private volatile static Singleton instance = null;
//静态工厂方法
public static Singleton getInstance() {
if (instance == null) { //双重检测机制
synchronized (Singleton.class){ //同步锁
if (instance == null) { //双重检测机制
instance = new Singleton();
}
}
}
return instance;
}
}