跳至主要內容

java基础

HeChuangJun约 4166 字大约 14 分钟

.1. Java特点、实现原理、JVM、JDK、JRE区别、jdk1.8新特性

一门面向对象、跨平台的编程语言

Java编译器将源代码编译成平台无关的字节码文件class,由对应平台的JVM将字节码文件解释成机器码并运行,实现“一次编写,到处运行”

Java Virtual Machine/Java虚拟机,负责运行Java程序
Java运⾏时环境。包括JVM和Java类库
Java Development Kit/java开发工具。包括JRE、编译器javac、文档生成工具Javadoc等

口日lsp
接口(default修饰)默认方法和静态方法
日期时间API:LocalDate/LocalTime/LocalDateTime time = LocalDate/LocalTime/LocalDateTime.now();
Lambda表达式:把函数作为方法参数 简化代码。函数式接口:@FunctionalInterface修饰能缩写成Lambda,如Runnable,Comparator,Callable等。new Thread( () -> print("a") ).start();

Optional类:用于解决空指针异常

Optional<String> optional = Optional.of("a");
optional.isPresent()get()orElse("b");//"a"
optional.ifPresent((s) -> print(s));// "b"

Stream API:Lambda表达式操作集合类。对集合做中间操作(filter、map、flatMap、distinct、limit、peek)返回Stream流或终端操作(any/all/noneMatch、collect、count、findAny/First、forEarch、min、max、reduce、toArray、sorted)返回结果

.2. 数据类型、默认值、越界√存储高精度整数、定点数/货币、汉字?√自动/强制类型转换?运算符&&和&区别,计算2x8、Math.round(-1.5/-1.5),自增/减、计算i=i++,switch表达式?break、continue、this作用、访问控制符范围?final、finally、finalize区别?

datatype.png
datatype.png

整型类型超出表示范围会出现i+1<i、i-1>i√

BigInteger、BigDecimal/int表示分、char(Java用2字节的Unicode编码表示汉字和字母)

自动类型转换:范围小的数据类型赋值给范围大的数据类型,反之则是强制转换

都表示逻辑与运算,只有两边表达式都为true时结果才为true
&&:有短路功能,当第一个表达式为false,则不再计算第二个
&:两个表达式都执行。当两边表达式不是Boolean类型表示按位运算

2<<3。位运算,左移3位等价于乘以2^3

2/-1等价于Math.floor(x+0.5)加0.5后向下取整

++/--i,先自增/减,再赋值;i++/--相反

i不变,因为自增运算用临时变量接收i值再自增,等价于int temp = i;i++;i = temp;

byte、short、int、char、enum枚举、String

break结束循环,continue跳过本次循环执行下次循环

代表对象本身。引用对象本身;区分重名参数和成员变量;调用本类构造函数

private本类,default同包、protected同包和子类,public所有

final修饰符,修饰类/方法/变量不能被继承/重写/修改且声明时必须初始化。不可变指变量的引用不可变,引用指向的内容的可变
finally:无论(try)是否抛出异常,finally代码都会执行。除了finally中抛出异常或System.exit()退出程序,用于释放资源(I/O)
finalize:Object类的方法,在垃圾回收前调用一次。finalize中强引用对象能避免垃圾回收。不推荐用于管理对象生命周期

.3. 面向对象OOP特性?概念,和面向过程OPP区别?创建对象方式、初始化过程√深/浅拷贝实现?重载/写区别?√抽象类和接口异同?选用?√成员/局部变量、静态/实例变量/方法区别?

封装:把对象的属性私有化并提供外界访问的方法 安全性高
继承:在已存在的父类定义基础上建立子类的方法
子类能直接使用、重写或者扩展从父类继承来的属性和方法。代码复用,扩展性强,但耦合度增强
多态:引用变量的具体类型和调用的方法在编程时不确定,运行时才确定
子类继承父类并重写父类方法、父类引用指向子类对象;类实现接口并实现接口方法、类引用指向接口;~

面向对象:将事物抽象为对象,用类和对象模拟真实世界的关系和操作
面向过程:按步骤分析问题,用函数实现每个步骤,按顺序调用

关注点:面向对象关注对象及其关系,步骤和过程
数据和函数关系:面向对象将数据和方法封装在对象中,数据和函数分离
扩展性与维护性:面向对象通过~提升扩展性和维护性,较弱
关数矿

//用new关键字
A a = new A(); 
//用Class类的newInstance方法
Class clazz = Class.forName("A"); A a = (A) clazz.newInstance();
//用clone方法
A a2= (A) a.clone();
//用ObjectInputStream类的readObject()方法
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
oos.writeObject(a);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
A a2 = (A) ois.readObject();

父类静态(属性->代码块)->子类 父类非静态(属性->构造代码块)->构造方法->子类

浅拷贝:拷贝对象的基本数据类型变量和引用数据类型变量的地址值,不拷贝引用类型变量指向堆中的对象 实现Cloneable接口并重写Object类的clone方法 性能要求高且不需修改引用对象
深拷贝:完全拷贝对象,包括引用类型变量指向堆中的对象 实现Serializable接口 ObjectInputStream和ObjectOutputStream 对象层次深且需要独立修改引用对象

方法重载overload:同一个类中名称相同、参数类型或个数或顺序不同的方法
方法重写override:父子类中方法名、参数列表、返回值相同、方法体不同的方法
返回值、异常小于等于,少于等于父类;访问修饰符大于等于父类
static、final、private方法,构造器不能被继承,因此不能重写

一狗屎剧
同:包含抽象方法;重写完抽象方法才能创建对象
异:类只能继承一个父类,能实现多个接口
抽象类能定义构造函数、私有、具体方法;接口不能、jdk9+、8+支持

优先选接口,定义子类公共实现时用抽象类

语法:成员变量包括类变量或者实例变量,定义在类中,局部变量定义在方法中
内存存储方式:实例变量存储在堆内存中,类变量存储在方法区,~存储在栈内存
访问修饰符:成员变量能被public、private、static修饰,~不能,都能被final修饰
初始值:成员变量(除final修饰外)没有初始值时有默认值,~没有默认值
生命周期:成员变量随对象存在,局部变量随方法调用消失
鱼类方畜生

静态变量/方法:被static修饰,类级别,内存中只有一个副本/不能访问类的非静态成员变量和方法
实例变量/方法:对象级别,通过对象访问/能访问类的所有成员变量和方法

.4. ==和equals区别?hashcode方法作用?两个对象的hashCode方法相同,equals方法一定为true吗?为什么重写equals方法一定要重写hashCode方法?自动装/拆箱及设计理由?int和Integer区别?√==比较Integer√String转成Integer原理?参数传递时传值还是传引用?

==:基本类型比较数值,引用类型比较内存地址
equals:不重写等价于==,重写后比较两个对象内容是否相等。String、Integer重写了

返回由对象内存地址计算出来的int类型的哈希码,重复率低,用作键值对的键,查询效率高

不一定。因为存在哈希冲突,为了解决哈希冲突问题,判断对象是否相等时要比较键的哈希码和equals方法。如果哈希码相同但equals为false,则两个对象不相等

保证集合能正确地存储和查找对象:不重写时,相同对象可能有不同哈希码,存储在集合不同的位置,导致集合元素重复或者找不到元素

自动装箱:Java编译器将基本数据类型转化为包装类。反之则是自动拆箱

简化代码,因为jdk1.5要手动将基本数据类型转成包装类放入集合中

类型:Integer是引用数据类型,int是基本数据类型
内存存储方式:Integer对象存储在堆内存中,引用保存在栈内存中,~存储在栈内存中
默认值:Integer默认值是null;0
语法:Integer必须实例化才能用;不需要
累累墨鱼

除了Integer i = 127 == Integer j=127,其他都是false
new Integer:Integer引用指向堆中的地址
Integer i = 0 ~java常量池中的对象或者Integer缓存池中的Integer对象-128-127

Integer.parseInt/valueOf(String s)最终调用parseInt(String s, int radix)字符串遍历负值累减,21 = -1 x (-1 + -2 x 10)

基本类型和引用类型参数都是值传递,引用类型传递是对象的引用

.5. String创建方法区别?√特点及设计原因?拼接实现原理?与StringBuilder、StringBuffer区别?√

String str1 = "abc" 在字符串常量池中找abc字符串对象,没有则创建;
String str2 = new String("abc") ~,在堆中创建str2对象,引用指向abc字符串对象

引用类型不能被继承,类被final修饰,不可变类,字符串内容不可改变,因为底层char数组(jdk1.9+改为byte数组)被final修饰。字符串变量的地址值可以改变

节省内存:字符串值在常量池中不重复创建,只引用已存在的对象
性能优化:字符串不变性保证了hash码的唯一性,允许HashMap缓存HashCode,不必重复计算
安全性:字符串常用作网络URL和文件路径等参数,可变则有安全隐患

String:JDK1.8前拼接结果在常量池中如果不存在,则会生成新对象,大量字符串拼接时浪费内存,后改为StringBuilder的append处理
StringBuilder:用于单线程频繁修改字符串内容,直接修改底层char数组,如拼接、替换,不产生新对象,效率高
StringBuffer:线程安全版StringBuilder,方法加synchronized;效率低

.6. Error和Exception区别?异常处理方式?过程?

Exception.jpg
Exception.jpg

(非)受检异常:编译器(不)会检查且(非)必须处理的异常
Exception中除RuntimeException及其子类之外的异常都是受检异常

Throwable
Error:系统级异常。如内存空间不足、方法调用栈溢出
Exception:能处理的异常
编译期异常Checked Exception
运行时期异常RuntimeException及其子类异常,修改代码解决

方法内异常对象throw;方法上throws抛出多个异常类,抛给调用者处理
try catch捕获异常

catch return-> finally return->try return(catch和finally不影响return变量值)

.7. IO?字节/字符流区别?InputStream不能重复读取原因及解决?√BIO、NIO、AIO区别?(反)序列化?零拷贝?

InputStream/Reader: 字节/字符输入流,所有输入流的基类
OutputStream/Writer: 字节/字符输出流。~出~

类图
IO.jpg
IO.jpg

字节流以字节为单位、字符流以2字节的字符为单位输入输出数据,支持多国语言
音频、图片、歌曲使用字节流,中文文本使用字符流

InputStream的数据源(如网络连接、文件等)可能不支持随机访问。例如网络流读取数据后不能返回

用ByteArrayOutputStream保存字节数据
public class InputStreamCacher {  
    private ByteArrayOutputStream byteArrayOutputStream = null;
    public InputStreamCacher(InputStream inputStream) {
        byteArrayOutputStream = new ByteArrayOutputStream();  
        byte[] buffer = new byte[1024];    
        int len;    
        try {  
            while ((len = inputStream.read(buffer)) > -1 ) {    
                byteArrayOutputStream.write(buffer, 0, len);    
            }  
            byteArrayOutputStream.flush();  
        } catch (IOException e) {  
            logger.error(e.getMessage(), e);  
        }    
    }
    public InputStream getInputStream() { 
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());  
    }  
}  
InputStreamCacher  cacher = new InputStreamCacher(inputStream);  
InputStream stream = cacher.getInputStream();

BIO:同步阻塞模型。服务器处理I/O请求时,线程会阻塞,直到I/O操作(accept、read、write都会阻塞)完成。实现模式为一个线程处理一个连接,用线程池减少资源消耗。用于连接数较少的场景。基于Socket和ServerSocket
NIO:同步非阻塞模型。通过Selector轮询多个通道Channel,实现非阻塞读取和写入数据(select阻塞,accept、read、write都会不阻塞)。即使I/O操作没有完成,线程也不会阻塞。实现模式为一个线程通过seletor管理多个连接,Selector轮询到有I/O请求时才处理。用于高并发IO的场景。基于SocketChannel和ServerSocketChannel
AIO:异步非阻塞模型。基于事件和回调机制,I/O操作由操作系统异步处理完成后通过回调通知程序。实现模式为CompletionHandler异步回调处理I/O操作。用于连接数较多且连接时间长的场景

序列化Serialization:把对象转为二进制流,反之则是反序列化
场景:将对象保存到文件或者数据库、网络传输等
Serializable接口只是标记,推荐实现,避免有些场景报错
serialVersionUID用于标识类的版本。保证序列化和反序列化时类的一致性。没有指定则根据类信息自动生成。如果没有指定又改了类结构,如增加成员变量,则反序列化失败
序列化不包含transient、static修饰的变量。transient不能修饰类和方法
用ObjectOutputStream和ObjectInputStream、jackson、fastjson序列化

在不修改数据前提下,减少从内核缓冲区到用户缓冲区,再从用户缓冲区到内核缓冲区两次数据CPU拷贝和用户态与内核态的两次切换,直接在内核态完成数据拷贝。减少CPU和内存的使用,提升性能
传统read操作将数据从内核空间的文件缓冲区拷贝到用户空间的缓冲区。write操作将数据从用户空间的缓冲区拷贝回内核空间的socket缓冲区,再通过网络传输。
实现方法
mmap+write(RocketMQ):mmap将内核中读缓冲区地址与用户空间缓冲区地址进行映射,实现内核缓冲区与用户缓冲区的共享。write函数直接在内核态完成数据拷贝,用于大文件传输,小文件可能出现碎片
sendfile(Kafa):建立两个文件之间的传输通道。在内核缓冲区和socket缓冲区完成CPU拷贝

.8. 泛型?优点?擦除原因?原理?List泛型区别?

generics java特性,本质参数化类型
编译时检查类型安全;自动类型转换,无需显式转换或使用instanceOf,简化代码
向下兼容
编译时会擦除所有类型信息,运行时不保留类型相关信息
List<? extends T>接受任何继承自T的类型的List
List<? super T>接受任何T的父类构成的List

//泛型类。实例化时要指定具体类型
Generic<Integer> genericInteger = new Generic<Integer>(123456);
public class Generic<T>{
    private T key;
    public Generic(T key) {this.key = key;}
    public T getKey(){return key;}
}
//泛型接口
public interface Generator<T> {
    public T method(T key);
}
class GeneratorImpl<T> implements Generator<String>{
    @Override
    public String method() {}
}
//泛型方法
public static <E> void printArray(E[] inputArray){}
Integer[] intArray = { 1, 2, 3 };
printArray( intArray  );

.9. 注解?

提供元数据的机制,给类、方法、字段、参数等代码元素附加信息
生命周期分类
RetentionPolicy.SOURCE:不写入class文件,给编译器用@Override,lombok注解
~.CLASS:写class文件,运行时不保留
~.RUNTIME:写class文件,反射获取注解信息@Autowired,AOP注解

.10. 反射?优缺点?场景?Class.forName和ClassLoader区别?

允许程序在运行时动态地获取类的信息、调用对象的方法、访问或修改对象的字段和创建对象实例
优点:运行时类型判断,动态加载类,代码灵活
缺点:反射相当于解释操作,性能比直接的代码差

使用Class.forName()通过反射加载数据库的驱动连接数据库
Spring通过XML配置反射装载Bean
Java类解析xml或properties内容,得到对应实体类的字节码字符串以及相关的属性信息
工厂模式通过反射根据全限定类名获得类的Class实例

原理:JVM加载字节码时将类型信息加载到方法区,反射用于获取并操作这些信息
javareflect.png

都将class文件加载到JVM,对类进行解释
Class.forName会执行类中的static块
ClassLoader在newInstance才执行