1.java的跨平台原理
java通过不同系统、不同版本、不同位数的java虚拟机来屏蔽不同的系统指令集差异而对外提供统一的接口,只需要按照接口开发即可。如果我系统需要部署到不同环境时,只需要在系统上面安装对应版本的虚拟机即可。
2.搭建有一个java开发环境的步骤
java开发环境需要什么 JDK、eclipse、tomcat
3.讲一下Java中int数据占几个字节
int占4个字节,32位
4.面向对象的特征
封装、抽象、继承、多态
封装:张三这个人,他的姓名等属性,要有自己提供的获取或改变的方法来操作。setName(),getName()
抽象:把现实生活中的对象,抽象为类 张三、李四都是人
继承:把已经存在的内容作为自己的内容,并可以加入新的内容
多态:有继承,有重写,有父类引用指向子类的对象 Animal a = new Cat(); 多态是动态绑定的,是运行时行为
5.有了基本数据类型,为什么还需要包装类型
装箱:把基本数据类型转为包装类型 Integer.valueOf()方法装箱
拆箱:把包装类型转为基本数据类型
java是一个面向对象的语言,基本的数据类型不具备面向对象的特性。
6.==和equals有什么区别?
==用来判断两个变量的值是否相等,变量可以分为基本数据类型变量、引用变量。
如果是基本数据类型的变量直接比较而引用类型需要比较对应的引用的内存的首地址。
equals用来比较两个对象长得是否一样,判断两个对象的某些特征是否一样,实际上时调用对象的equals方法进行比较。
7.String和StringBuider的区别?StringBuffer和StringBuilder的区别?
在java中提供三个类操作字符串
String是内容不可变的字符串。String str=new String("bbb");String底层使用了一个不可变的字符数组,使用final修饰
而StringBuilder和StringBuffer是内容可以改变的字符串,StringBuffer和StringBuilder底层使用的是可变的字符数组,最经典的就是追加append(),拼接字符串
String c="a"+"b";创建两个对象
StringBuilder sb=new StringBuilder();sb.append("a").append("b");
StringBulder是线程不安全的,效率较高,StringBuffer是线程安全的,效率较高。
8.java中的集合?
java中的集合
map,set,list
map:HashMap,LinkedHashMap,TreeMap
Set:HashSet,LinkedHashSet,TreeSet
List:ArrayList,LinkedList
存储值的分为List,Set
存储key-value的为map
List是有序的,可以重复的
Set是无序的,不可以重复的,根据equals和hashcode判断,如果一个对象要存储在set中,必须重写equals和hashCode方法
9.ArrayList和LinkedList区别
ArrayList使用的是数组,LinkedList使用的是链表
ArrayList底层使用的是数组,初始大小是10,插入新元素时,会判断是否需要扩容,扩容的步长是0.5倍原容量,扩容方式是利用数组的复制。
LinkedList使用的是双向链表,有一个内部类,用来存放元素本身以及前后两个单元的引用。
ArrayList查询比较快,LinkedList插入和删除比较快
10.HashMap和HashTable区别,HashTable和ConcurrentHashTable区别
HashMap和HashTable都可以使用存储key-value的数据
HashMap是可以把null作为key和valued的,而HashTable是不可以的
HashMap是基于哈希表,底层结构是由数组实现的.
HashMap添加元素时,根据键值key计算hash值得到插入的数组索引,如果table[i]为空,直接插入,如果不为空,判断key是否存在,如果存在直接覆盖,如果不存在,判断table[i]是不是红黑树,如果是直接插入,如果不是遍历链表准备插入,判断链表长度是否大于8,大于8转为红黑树插入, 否则链表插入
当hashmap中的元素个数超过数组大小*loadFactor时,就会进行数组扩容
HashMap是线程不安全的,效率高,HashTable是线程安全的,效率低
既想要线程安全又想效率高
ConcurrentHashTable把整个map分成n个segment,使用多个锁,每个段其实就是一个小的hashTable,有自己的锁。
11.拷贝文件的工具类使用字节流还是字符流
我们拷贝的文件不确定是只包含字符流,有可能有字节流(图片、声音、图像),为了考虑通用性,要使用字节流
12.接口与抽象类的区别
类可以实现多个接口但只能继承一个抽象类
接口里面的方法都是public的,抽象类允许privated、protected方法
13.内存溢出是怎么回事?
程序在申请内存时,没有足够的内存空间。程序在申请内存后,无法释放已经申请的资源
可能的原因:
- 程序中存在死循环
- 静态变量和静态方法太多了
- 大对象过多:java中的大对象是直接进入老年代的,然后当多个大对象同时工作时造成的程序的可用内存非常小。
- 程序分配内存过小
14.NIO是什么?适用于何种场景
NIO是为了弥补IO不足而诞生的,非阻塞IO,选择器,缓冲及管道
适用于小数据,多连接
NIO使用双向通道进行数据传输,NIO有三大核心:管道,缓冲区,选择器,传统IO基于字节流和字符流进行操作,而NIO基于通道和缓冲区进行操作,数据总是通过通道读到缓冲区,或者从缓冲区写入到通道中,选择器用于监听多个通道的事件。
io多路复用
15.final,finally,finalize区别
final定义类、方法、字段的修饰符,表示类不可被继承,方法不能被重写,字段不能被修改
finally是异常处理机制的关键字,表示最后被执行
finalize是Object的一个方法,在对象被虚拟机回收时会判断是否执行该方法,当对象没有覆盖finalize方法或者finalize方法已经被调用过,就视为没有必要执行。
16.创建一个对象的方式
1.new()
Hello hello=new Hello();
2.clone方法
Hello h2 = (Hello) h1.clone();
3.反射机制
Hello hello=new Hello();
try {
Hello hello =(Hello) Class.forName("test.Hello").newInstance();
hello.sayHello();
}catch (Exception e){
System.out.println(e);
}
try {
Hello hello = (Hello) Class.forName("test.Hello").getConstructor().newInstance();
hello.sayHello();
}catch (Exception e){
System.out.println(e);
}
4.序列化
HelloA h=new HelloA();
ByteArrayOutputStream fos=null;
ObjectOutputStream oos=null;
ByteArrayInputStream fis=null;
ObjectInputStream ois=null;
try{
//序列化
fos=new ByteArrayOutputStream();
oos =new ObjectOutputStream(fos);
oos.writeObject(h);
//反序列化
fis=new ByteArrayInputStream(fos.toByteArray());
ois=new ObjectInputStream(fis);
HelloA h1=(HelloA)ois.readObject();
h1.sayHello();
}catch (Exception e){
}finally {
try{
fos.close();
fis.close();
oos.close();
ois.close();
}catch (Exception e2){
System.out.println(e2.getMessage());
}
}
17.什么是java序列化,如何实现java序列化
原理是将对象写入流中,再从流中还原
对象中的成员对象也是可以序列化的,但是通过transient关键字标识不序列化
通过序列化进行深拷贝,从中还原对象
常用的序列化手段 二进制序列化:Protobuf、Kryo、Hessian 文本的:JSON、XML
18.静态内部类和内部类的区别
- 静态内部类可以有静态成员(方法,属性),而非静态内部类则不能有静态成员(方法,属性)。
- 静态内部类只能够访问外部类的静态成员,而非静态内部类则可以访问外部类的所有成员(方法,属性)。
- 实例化一个非静态的内部类的方法:先生成一个外部类对象实例 OutClassTest oc1 = new OutClassTest(); 通过外部类的对象实例生成内部类对象 OutClassTest.InnerClass no_static_inner = oc1.new InnerClass();
- 实例化一个静态内部类的方法:不依赖于外部类的实例,直接实例化内部类对象 OutClassTest.InnerStaticClass inner = new OutClassTest.InnerStaticClass(); 调用内部静态类的方法或静态变量,通过类名直接调用 OutClassTest.InnerStaticClass.static_value OutClassTest.InnerStaticClass.getMessage()
19.为什么要重写equasl方法
有时,我们需要两个不同对象只要是某些属性相同就认为它们equals()的结果为true。
为什么要重写hashCode方法
判断的时候先根据hashcode进行的判断,相同的情况下再根据equals()方法进行判断。.如果两个对象equals结果为true,那么hasCode的值必须相同。
20.JAVA泛型底层实现原理
Java的泛型是伪泛型。在编译期间,所有的泛型信息都会被擦除掉。正确理解泛型概念的首要前提是理解类型擦出(type erasure)。
Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。
如在代码中定义的List<object>和List<String>等类型,在编译后都会编程List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。