JDK、JRE、JVM的区别
JDK:java Development kit java开发工具
JRE:java Runtime Environment java运行时环境
JVM:java virtual Machine java虚拟机
JDK包括java的开发环境和运行环境,就是说JDK包含了JRE,如果需要使用Java来开发,需要安装JDK,如果只是运行java程序,则只需要安装JRE即可。
==和equals
==对比的时栈中的值,基本数据类型是变量值,引用类型是堆中内存对象的地址
equals:Object中默认也是采用==比较,通常会重写
public boolean equals(Object obj) {
return (this == obj);
}
String类重写的equals
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
上述代码可以看出,String类被复写的equals()方法其实是比较两个字符串的内容
练习
public class StringDemo {
public static void main(String[] args) {
String str1="Hello";
String str2 = new String("Hello");
String str3=str2;
System.out.println(str1==str2); //false
System.out.println(str2==str3); //true
System.out.println(str1==str3); //false
System.out.println(str1.equals(str2)); //true
System.out.println(str2.equals(str3)); //true
System.out.println(str1.equals(str3)); //true
}
}
简述final作用、为什么局部内部类和匿名内部类只能访问局部变量final变量
- 修饰类:表示类不可被继承
- 修饰方法:表示方法不可被子类覆盖,但可以重载
- 修饰变量:表示变量一旦被赋值就不可以更改它的值
(1)修饰成员变量
- 如果final修饰的时类变量,只能在静态初始化块中指定初始化值或者声明该类变量时指定初始值
- 如果修饰的时成员变量,可以在非静态初始化块、声明该变量或者构造器中执行初始值
(2)修饰局部变量
- 系统不会为局部变量进行初始化。局部变量必须由程序员显式初始化。因此使用final修饰局部变量时,即可以在定义时指定默认值(后面的代码不能对变量在赋值),也可以不指定默认值而后面的代码堆final变量赋初值(仅一次)
package test;
public class FinalVal {
final static int a=0; //在声明的时候赋值,或者在静态代码块赋值,类变量
// static {
// a = 0;
// }
final int b=0; //成员变量
// {
// b=0;
// }
public static void main(String[] args) {
final int localA; //修饰局部变量时,不一定要在声明的时候赋值,只要在使用之前赋值就行,并且赋值之后不能修改
localA=0;
// localA=1; 错误
}
}
(3)修饰基本类型数据和引用类型数据
- 如果是基本类型数据的变量,其数值一旦初始化之后便不能修改;
- 如果是引用类型的数据,在对齐初始化后不能再让他指向另一个对象,但引用的值是可变的。
package test;
public class FinalReferenceTest {
public static void main(String[] args) {
final int[] iArr = {1, 2, 3, 4};
iArr[2] = -3;
// iArr=null; 非法,对iArr不能重新赋值
final Person person = new Person(25);
person.setAge(24);
// person = null; 非法
}
static class Person {
int age;
public Person(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
为什么局部内部类和匿名内部类智能访问final对象
package test;
public class FinalReferenceTest {
public static void main(String[] args) {
}
public void test(final int b) {
final int a = 10;
//匿名内部类
new Thread() {
public void run() {
System.out.println(a);
System.out.println(b);
}
}.start();
}
class OutClass {
private int age = 12;
public void outPrint(final int x) {
class InClass {
public void InPrint() {
System.out.println(x);
System.out.println(age);
}
}
new InClass().InPrint();
}
}
}
首先需要知道的一点是:内部类和外部类是处于同一级别的,内部类不会因为定义在方法中就会随着方法的执行完毕而被销毁,这里就会产生一个问题:当外部
类的方法结束时,局部变量就会被销毁了,但是内部类对象还存在(还有对象在引用它),这就会使得内部类对象会去访问一个不存在的变量,为了解决这个问
题,就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡后,内部类任然可以访问它,实际访问的是局部变量的copy。这样就好像延长了局部
变量的生命周期。
将局部变量复制为内部类的成员变量时,必须保证两个变量是一样的,也就是说如果我们在内部类修改了成员变量,方法中的局部变量也得跟着改变怎么解决
这个问题呢
就将局部变量设置为final,对他初始化后,我就不让你再去修改这个变量,就保证了内部类的成员变量和方法的局部变量的一致性,这实际也是一种妥协。使
得局部变量与内部类建立的拷贝一致。
String、StringBuffer、StringBuilder的区别及使用场景
String是final修饰的,不可变,每次操作都会产生新的String对象(例如字符串拼接)
StringBuffer和StringBuilder都是在原对象上操作
StringBuffer是线程安全的,StringBuilder线程不安全的
StringBuffer方法都是synchronized修饰的
性能:StringBuilder>StringBuffer>String
场景:经常需要改变字符串内容时使用后面两个
优先使用StringBuilder,多线程使用共享变量时使用 StringBuffer
final在java中的作用
final修饰的类叫最终类,该类不能被继承
final修饰的的方法不能被重写
final修饰的变量叫常量,常量必须被初始化,初始化之后值不能被修改
java中的Math.round(-1.5)等于多少
等于-1,里面的数+0.5向下取整。
String属于基础的数据类型吗
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、
double,而 String 属于对象。
Java中操作字符串都有哪些类,它们之间有什么区别
操作字符串的类有String,StringBuffer、StringBuilder
String与后两个的区别在于String是不可变的对象,每一次操作都会产生新的String对象,然后把指针指向这个新的对象,而后面两个都可以在原来的对象上操作,所以经常要改变字符串内容的情况下最好不要用String。
StringBuffer是线程安全的,StringBuilder是线程不安全的,但是StringBuilder的性能优于StringBuffer的,多线程环境下最好使用StringBuffer。单线程推荐使用StringBuilder
抽象类一定要有抽象方法吗
不是,抽象类不一定有抽象方法,但抽象方法一定是存在抽象类里面的。
普通类和抽象类有哪些区别
普通类不能包含抽象方法,抽象类可以由抽象方法。
抽象类不能直接被实例化(可以通过继承抽象类进行实例化),普通类可以直接实例化。
抽象类不能使用final修饰吗
抽象类不能被final修饰,因为抽象类不能实例化,就是让其他类来继承使用的,如果设置成final,就不能被继承,产生矛盾,编译也会报错。
抽象类和接口的区别
抽象类可以有默认的方法实现,接口不能有默认的方法实现
实现:抽象类的子类使用extend来继承,接口必须使用implements来实现接口
构造方法,抽象类可以有构造函数。接口不能有
抽象类可以有main方法,并且能运行它,接口不能有main方法。
实现数量:类可以实现很多接口,但是只能继承一个抽象类
访问修饰符,接口的方法默认是public修饰,抽象类的方法可以是任意访问修饰符
java中IO流分为多少种
按功能来分:输入流、输出流
按类型来分:字节流,字符流
字节流和字符流的区别是:字节流按8位传输亿字节位单位输入输出数据,而字节流是16位
BIO、NIO、AIO有什么区别
BIO:Block IO同步阻塞iIO,就是我们平常使用的传统IO,他的特点是模式简单,使用方便,并发处理能力低
NIO:new IO同步非阻塞IO,是传统IO的升级,客户端和服务端通过channel(通道)通信,实现了多路复用
AIO:Asynchronous IO是NIO的升级,也叫NIO2,实现了异步非阻塞IO,异步IO的操作基于时间和回调机制
Java的容器有哪些
Java容器分为Collection和Map两大类,其下又有很多子类,如下所示
Collection和Collections有什么区别
Collection是一个集合接口,它提供了对集合对象进行操作的通用接口方法,所有集合都是它的子类,比如List,Set等
Collections是一个工具类,里面有很多静态方法,不能被实例化(构造方法被private修饰)在java的Util包下,是一个工具类。l例如提供排序方法Collectios.sort(list)。
List、Set、Map之间的区别是什么
List:有序、可重复、来纳许存储,查找快、增删慢
set:无序,不可重复
Map:通过键值来存储元素,键唯一,值不唯一,对 map 集合遍历时先得到键的 set 集合,对 set 集合进行遍历,得到相应的值。
HashMap和HashTable有什么区别
存储:HashTable可以存储key和value都为null的,而HashTabel不允许
线程安全:hashTable是线程安全的,HashMap不是线程安全
当在单线程的环境下,推荐使用HashMap,在多线程的情况下,HashTable的类注释推荐使用ConcurrentHashMap来存储
如何决定使用HashMap还是TreeMap
对于在Map中插入、删除、定位一个元素这类操作,HashMap是最好的选择、因为相对而言HashMap的插入会更快,但如果你要对key集合进行有序的遍历,可以选择TreeMap(基于红黑树实现)。
说一下HashMap的实现原理
HashMap基于Hash算法实现的,通过put(key,value)来存储,get(key)来获取当传入key时,HashMap会根据key.hashCode计算出hash值,根据hash值将value存在bucket,当计算的hash值一样时,我们称之为hash冲突,,HashMap的做法是用链表和红黑树来存储相同的hash值的value,当hash冲突的个数较少时,使用链表,否则使用红黑树(红黑树就是平衡树,元素较多时比链表查询效率高)。
说一下HashSet的实现原理
HashSet 是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现
比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允
许重复的值