Java面试知识点(一)——Java基础知识
1.Java
Java是面向对象编程语言,不仅吸收了c++的优点,还倔弃了c++里面很难理解的多继承、指针等相关概念
- 因此java语言功能强大且简单易用
- 面向对象(封装、继承、多态)
- 平台无关性(java虚拟机实现平台无关性)
- 支持网络编程、多线程
- 健壮性、安全性
2.JDK1.5之后的3大版本
- Java SE(J2SE,Java 2 Platform Standard Edition,标准版)
它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用Java程序。 - Java EE(J2EE,Java 2 Platform Enterprise Edition,企业版)
在Java SE的基础上构建,提供Web服务器、组件模型、管理和通讯API,可以用来实现企业级的面向服务体系结构和web2.0应用程序。 - Java ME(J2ME,Java 2 Platform Micro Edition,微型版)
为在移动设备和嵌入式设备(手机、电视机机顶盒、打印机)上运行的应用程序提供一个健壮且灵活的环境。
3. JVM、JRE、JDK三者的关系
JVM
Java Virtual Machine 意为java虚拟机,Java程序需要运行在Java虚拟机上,每个平台有自己的虚拟机,所以Java语言具有跨平台性。
JRE
Java Runtime Environment 包括Java虚拟机和Java程序所需的核心类库等。
核心类库:java.lang包:包含了运行Java程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统缺省加载这个包。
JDK
Java Development Kit是提供给Java开发人员使用的,包含了Java的开发工具(编译工具javac.exe、打包工具、jar.exe)
4.字节码
概念: java源代码经过虚拟机编译器编译后产生的文件(.class)文件
好处: Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。Java源代码-->编译器-->字节码.class文件-->JVM解释器解释运行-->二进制码-->程序运行
5.Java和C++的区别
- 都是面向对象语言,都支持封装、继承、多态
- Java不提供指针来直接访问内存,内存更加安全
- Java中类不能多重继承,但是接口可以多继承
- Java中有自动内存管理机制,不需要自己手动释放无用内存
5.Java中的权限修饰符
- private:同一个类可见(不能修饰类)
- default:同一个包可见
- protected:同一个包内的类和所有子类(不能修饰类)
- public:所有类可以见
6.Java中常见的关键字
1. static关键字
static修饰的方法或者变量不需要实例化对象访问,而是随着类的加载而加载
- static修饰的代码块-------静态代码块
- static修饰的方法--------静态方法,静态方法只能访问静态方法,不能访问非静态,静态方法不能访问非静态变量
- 非静态可以访问静态
- 只加载一次
2.final关键字
- final修饰的类不能被继承
- final修饰的方法不可被重写
- final修饰的属性不能重新赋值
3.abstract关键字
- abstract修饰的类不能实例化对象
- 抽象类可以没有抽象方法,但是有抽象方法的一定是抽象类
- 抽象方法中不能有方法体,必须被子类重写
- 抽象类的子类必须实现其父类的所有抽象方法、或者也是一个抽象类
- abstract不能修饰属性、局部变量
4.volatile关键字
volatile是Java中的一个类型修饰符,被设计用来修饰被不同线程访问和修改的变量。如果变量不加入volatile,导致无法编写多线程程序或者编译器失去大量优化的机会
5.native关键字
native修饰的方法是一个原生态方法,方法对应的实现不是在当前文件中,而是在用其他语言(c、c++)实现的文件中,
7.Java中的类
(一)同级类
(二)内部类
内部类是一个类当中的类,相当于在一个类中嵌套了另一个类
特点:内部类中可以调用外部类的属性和方法,而外部类不能调用内部类的属性和方法
1.静态内部类
- 作为类的静态成员,存在于某给类的内部
- 静态内部类虽然是外部类的成员,但是在未创建外部类的对象的情况下,可以直接创建静态内部类的对象。静态内部类可以引用外部类的静态成员变量和静态方法,但不能引用外部类的普通成员。
2.成员内部类
- 只有在创建了外部类的对象后,才可调用外部类的所有成员
3.局部内部类
- 存在于某个方法的内部
4.匿名内部类
- 可以继承抽象类或接口
- 存在于类的内部,但是没有名字
//语法
new 类或者接口的名字(){
}
class User{
public void show(Student student){
student.show();
System.out.println("User的show方法")
}
}
class Student{
public void show(){
System.out.println("Student的show方法")
}
}
public class test{
public static void main(String args[]){
User u = new User();
u.show(new Student(){
public void show(){
System.out.println("匿名内部类的show方法")
}
});
}
}
//运行结果
匿名内部类的show方法
User的show方法
8.抽象类和接口
(一)抽象类
- 抽象类中可以有构造方法
- 抽象类中可有普通属性和方法,静态属性和方法
- 抽象类有可以有抽象方法,抽象方法不能有方法体
- 有抽象方法的类一定是抽象类,抽象类不一定有抽象方法
- 抽象类中定义的方法需要子类实现,如果子类不实现,则子类也需要定义为抽象的。
- 抽象类不能被实例化
- 抽象类可以实现接口,但是不一定实现接口的方法。当抽象类不实现接口的方法时,继承该抽象类的非抽象类必须实现时抽象类的抽象方法和接口方法,当抽象类实现接口方法时,继承类就不用再实现接口的方法。因为抽象类和接口的方法都是abstract方法,抽象方法一定需要实现,在继承的类中总要有实现该方法。
(二)接口
- 接口中只能声明方法,不能声明方法体
- 接口中只有常量,如果定义变量,在编译时也会默认加上public static final
- 接口中的方法默认为public abstract
- 接口中没有构造方法,不能实例化对象
- 接口可以实现多继承
extends interface A,interface B
,但是不允许实现其他接口interface
- 接口中定义的方法都需要实现类来实现,如果实现类不能实现接口中的所有方法则实现类定义为抽象类(因为抽象类中可以存在抽象方法)
9.String、StringBuilder、StringBuffer
String
- 不可变的字符序列
- String声明为final的,不可被继承
- String实现了Serializable接口:表示字符串是支持序列化的
- 实现了Comparable接口:表示String可以比较大小
- String内部定义了final char[] value 用于存储字符串数据
String类与其他结构之间的转换
public class StringTest2 {
/*
string与基本数据类型包装类之间的转换
调用包装类的静态方法:parseXxx(str)
将基本数据类型、包装类 -->string
调用String重载的valueOf(xxx)
*/
@Test
public void test1() {
String s1 = "123";
//int num = (int)s1;错误的
int num = Integer.parseInt(s1);
String s2 = String.valueOf(num);
}
/*
String与char[]之间的转换
String---->char:调用String的toCharArray()
char---->String:调用String 的构造器
*/
@Test
public void test2() {
String s1 = "abc123";
char[] c1 = s1.toCharArray();
for (int i = 0; i < c1.length; i++) {
System.out.println(c1[i]);
}
char[] arr =new char[]{'h','e','l','l','o'};
String S2 = new String(arr);
System.out.println(S2);
}
}
StringBuffer
- 可变的字符序列;
- 线程安全的-效率低;
- 底层使用char[]数组存储
StringBuilder
- JKD5.0新增
- 线程不安全-效率高
- 底层使用char[]数组存储
扩容问题:
如果要添加的数据底层数组装不下,就需要扩容底层数组
默认情况下扩容为原来的2倍+2,同时将原有数组中的元素复制到新的数组中
这三个类的主要区别在于执行效率和线程安全性两个方面
1.执行效率:StringBuilder > StringBuffer > String
String 是一个final类不能被继承且为字符串常量,String对象一旦被创建便不可更改
String str = "abc";
str = str + "def";
System.out.println(str);
上面的代码创建了一个String 对象赋值为abc ,继续下一行后,JVM会再创建一个新的str对象赋值为abcdef,而之前的则被JVM的垃圾回收机制回收,所以str并没有更改,即String对象一旦创建不可更改。
所以在对String对象操作,实际上是不断创建和回收对象的过程,因此执行效率很慢。
StringBuilder sb = new StringBuilder();//底层创建了一个长度为16的数组 char[] value = new char[16];
sb.append("abc").append("def");
System.out.println(sb)
对象被建立以后将在内存中分配内存空间,并初始保存一个 null,通过 append 方法向 StringBuffer 和 StringBuilder 中赋值。
2.线程安全性
StringBuffer(线程安全的)
StringBuffer 中大部分方法由 synchronized 关键字修饰,在必要时可对方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致,所以是线程安全的。
StringBuilder(非线程安全的)
StringBuilder 的方法没有该关键字修饰,所以不能保证线程安全性。是 JDK1.5 新增的,该类提供一个与 StringBuffer 兼容的 API,但不能保证同步,所以在性能上较高。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。
10.装箱和拆箱
由基本数据类型转化成包装类是装箱(int------>Integer
)
由包装类转化为基本数据类型是拆箱(Integer------>int
)
基本数据类型----->值类型
包装类-------------->引用类型
11.Math类
Math类中有三个取整的方法:ceil
、round
、floor
ceil
:向上取整,Math.ceil(11.3) = 12
floor
:向下取整,Math.floor(11.7) = 11
round
:四舍五入,Math.floor(x+0.5)
即原来的数字+0.5然后再向下取整