面向对象及三大特性
答:面向对象是一种思想,将复杂问题简单化,把相关数据和方法当作一个整体来看。三大特性为封装继承和多态。
- 封装:将事物封装为一个类,减少耦合,隐藏细节。保留接口与外界联系,当接口内部改变时,不会影响外部的调用。
- 继承:从一个已知的类中派生一个新的类,新类拥有已知类的属性和方法,并能重写或覆盖来增加已知类的能力。
- 多态:一个程序中存在多个同名的不同方法。实现方式:子类对父类的覆盖、类对方法的重载、子类作为父类对象使用。
关于封装
对类进行内部处理,在get/set方法中进行内部逻辑封装,外部直接调用。
关于继承
覆盖@Override
覆盖=重写,即父类有方法A,子类拓展了方法A并加了新功能,则称之为子类覆盖或重写了方法A。
关于多态
重载Overload
一个类中存在多个同名的不同方法,这些方法参数个数、顺序和类型不同构成方法的重载。
构造器不能被重写,但能被重载
**只有返回值不同,不构成重载!**因为有时我们调用方法并不关心其返回值。
子类对象作为父类对象使用
涉及向上转型和向下转型。向上可以直接转,子类通父类。向下需要强制类型转换,父类不懂子类。
JDK、JRE和JVM
答:基本概念如下:
- JDK(Java Development Kit)开发工具包,java开发环境的核心组件,提供编译调试和运行java程序所有的工具和文件。
- JRE(Java Runtime Environment)java运行时环境,是JVM的实现,提供运行java程序的平台。JRE包含JVM。4
- JVM(Java Virtual Machine)java虚拟机,运行程序时,JVM将字节码转为机器码,提供内存管理、GC等功能。
区别和联系
- JDK是开发工具包,JRE是运行时环境
- JDK和JRE包含了JVM
- JVM是java编程核心,具有平台无关性。使得java程序能一次编写多次执行。
平台无关性如何实现
- JVM屏蔽了操作系统和底层硬件的差异
- Java面向JVM编程,先编译生成字节码文件,再交给JVM转为机器码
- java的语言规范也规定了基本数据类型的取值范围,无关平台差异
java是编译型还是解释型语言
答:java是先编译后解释执行的语言,不能单纯地归类。
抽象类和接口
答:主要区别有:
- 抽象类中可以有非抽象方法;接口中在JDK8之前只能是抽象方法,JDK8后提供了接口中方法的default实现
- 抽象类单继承,接口能实现多个父接口
- 抽象类中存在普通的成员变量,接口中只有初始化的static final常量,没有变量
- 抽象类的修饰符有public、protected,接口只能public修饰
- 抽象是对类的抽象,接口是对行为的抽象
如何选择使用
答:当需要定义抽象方法但不要额外的变量和方法时,用接口。反之,用抽象类。
基本数据类型和范围
答:java中有8种基本数据类型。
- byte:1字节 -27 ~ 27-1 => -128~127
- short:2字节 -215 ~ 215-1 => -32768 ~ 32767
- int:4个字节 -231 ~ 231-1,即-2147483648 ~ 2147483647
- long:8字节 -263 ~ 263-1,即-9223372036854774808 ~ 9223372036854774807
- float:4字节
- double:8字节
- char:2字节 0 ~ 216-1
- boolean:Java规范中没有规定其字节数
缓存池
答:new Integer(123) 与 Integer.valueOf(123) 的区别在于:
- new Integer(123) 每次都会新建一个对象;
- Integer.valueOf(123) 会使用缓存池中的对象,多次调用取同一个对象的引用。valueOf() 方法先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。
Java中的元注解
答:提供了4个元注解,作用是负责注解其他注解。
- @Target,注明注解用于什么地方。
- @Rentention,注明注解的生命周期,分为SOURCE, CLASS, RUNTIME三种策略。
- @Documented,注明是否将注解信息添加在java文档中。
- @Inherited,注明该注释和子类的关系。即一个类被@Inherited的注解标注,其子类也被这个注解标注。
注解的流程
答:作用:代替繁琐的配置文件,简化开发。
定义
定义注解类必须使用@interface
属性
value就是属性。指定属性后,使用注解时需要给属性赋值。
public @interface MyAnn {
String value();
int value1();
}
// 使用注解MyAnn,可以设置属性
@MyAnn(value1=100,value="hello")
public class MyClass {
}
注解处理器
TODO
反射机制
答:反射机制是指在运行中,任意一个类,都能知道这个类的所有属性和方法;任意一个对象,都能调用它的属性和方法。简而言之,动态获取和调用对象的属性和方法。
相关类
- Class:类,用于获取类的相关信息
- Field:成员变量,用于获取实例变量和静态变量
- Method:方法,用于获取类中的方法参数和类型
- Constructor:构造器,用于获取构造器的相关参数和类型
实例
public class Demo1 {
public static void main(String[] args) throws Exception {
String className = "com.bys.User";
// 获取Class对象
Class clazz = Class.forName(className);
// 创建User对象
User user = (User)clazz.newInstance();
// 和普通对象一样,可以设置属性值
user.setUsername("bys");
user.setPassword("123456");
System.out.println(user);
}
}
class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}
Exception和Error的区别
答:主要区别是:
- Exception是程序正常运行中预想到的可能发生的错误,需要捕获处理。其中又分为编译时异常和运行时异常。
- Error是程序正常运行中不可能发生的错误,不需要捕获处理。
异常捕获原则
- 捕获尽可能详细的错误,减少用Exception直接捕获
- 异常捕获需要日志模块的记录
- try-catch段落尽量精细,便于后期排查
JIT编译器
答:JIT(Just In Time Compile)即时编译器,把经常运行的代码编译成和本地平台相关的机器码并优化,包括逃逸分析、锁消除、空值检测消除等。
逃逸分析
答:逃逸分析的基本行为就是分析对象动态作用域。当一个对象在方法中被定义时,它可能被外部方法引用,例如作为参数传递,这种称为方法逃逸。作用是,经过分析,发现对象不被外界访问,经过JIT优化,把对象拆解成若干标量替换。
Java的值传递和引用传递
答:概括为:
- 值传递,传递对象的副本,即修改副本,不影响源对象。
- 引用传递,传递对象的引用,即修改引用对象,会影响源对象。
注意:**在Java中只有值传递!**因为方法得到的所有参数值都是拷贝,方法不能修改传递给他的任何参数变量的内容。
StringBuffer与StringBuilder的区别
答:StringBuffer是线程安全的(加了同步锁),StringBuilder是非线程安全的。StringBuilder有速度优势,但提升不高,又要冒多线程不安全的风险。所以:
- 操作少量的数据: 适用String
- 单线程操作字符串缓冲区下操作大量数据: 适用StringBuilder
- 多线程操作字符串缓冲区下操作大量数据: 适用StringBuffer
记不清的话用safe来记忆,buffer有safe的一部分,所以它是线程安全的。
Java中的泛型的理解
答:泛型是把确定类型的工作推迟到创建对象或者调用方法时才去确定的特殊类型。
泛型的意义
早期Java用Object表示任意类型,但会有强转问题,导致安全问题。所以提出泛型的概念,使得代码更加简洁,不用进行强转;程序更加健壮(只要编译时期没有警告,那么运行时期就不会出现ClassCastException异常);稳定性可读性更好,在建立集合时候限定类型。
泛型基础
泛型类
泛型类就是把泛型定义在类上,用户使用该类的时候,才把类型明确下来。
public class ObjectTool<T> {
private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
泛型方法
外界调用时传进来什么类型,返回值就是什么类型。
//定义泛型方法..
public <T> void show(T t) {
System.out.println(t);
}
泛型类的子类
分为子类明确和子类不明确
//子类明确
public class InterImpl implements Inter<String> {
@Override
public void show(String s) {
System.out.println(s);
}
}
//子类不明确
public class InterImpl<T> implements Inter<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
类型通配符
泛型提供了类型通配符 ?,表示匹配任意类型。在用这个时,必须注意:只能调用和对象无关的方法,不能调用和对象有关的方法,直到外界确定了具体的类型。
public void test(List<?> list){
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
通配符上限
表示List接收的元素只能是Number自身或子类。
List<? extends Number>
通配符下限
表示传递进来的只能是Type或其父类。
<? super Type>
通配符和泛型方法
这两者大多数时候是互通相等的。原则上参数间或参数和返回值间有依赖关系就用泛型方法,否则通配符。
//使用通配符
public static void test(List<?> list) {
}
//使用泛型方法
public <T> void test2(List<T> t) {
}
泛型擦除
在已经确定泛型类型的集合赋值给普通集合时,发生泛型擦除,即保留类型参数的上限。如List list传递给List list1,保留的是String的上限Object。
Java序列化与反序列化的过程
答:用transient修饰不想被序列化的变量(只能修饰变量)。
- 序列化:将对象转换为字节序列存储到硬盘上的过程
- 反序列化:把硬盘上的字节序列读取恢复成一个对象的过程
Java和C++的区别
答:联系和区别。
- 都是面向对象的语言,支持封装、继承和多态
- java不提供指针访问内存
- java的类是单继承,C++支持多重继承
- java有自动内存管理机制,不需要手动CG
- C/C++中的字符串和数组都自动加一个’\0’作为结束符,java中不需要
静态与非静态的区别?
答:静态是指用static关键字修饰的类、方法、字段等,非静态是指没有用static修饰的。
- 静态只能访问静态的,非静态既能访问静态的也能访问非静态的
- 静态的直接可以用类名调用,非静态的需要先实例化再调用。
- 静态变量存在常量池中,非静态成员变量在堆中
- 静态变量随类的加载而加载,消失而消失,非静态成员变量随对象创建而存在,消失而消失
equals方法和==的区别
答:区别
- 对于基本类型,==判断值相等,无equals()方法。
- 对于引用类型,==判断两个变量是否引用同一个变量即比较对象的地址,equals()判断引用对象是否等价。
equals()和hashCode()的关系
答:先解释两者的作用,再说联系。
equals()
判断两个对象是否相等
hashCode()
获取对象的哈希码(散列码),根据哈希码确定对象在哈希表中的索引
两者的关系
- 两个对象相等,hashCode()也一定相同;hashCode值相同,对象不一定相等
- 故而equals方法重写时,hashcCode也一定也要被重写,为保证两个对象的哈希值也相等