# 技术栈知识点巩固——Java
Posted MarlonBrando1998
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了# 技术栈知识点巩固——Java相关的知识,希望对你有一定的参考价值。
Hellow World
- 输入参数,在控制条打印出参数
package java.lang;
public final class System {
public final static PrintStream out = null;
}
package java.io;
public class PrintStream extends FilterOutputStream
implements Appendable, Closeable
{
// ...
public void println() {
newLine();
}
}
equals与==的区别
- 基本数据类型:
equals
不能比较基本数据类型的变量,==
比较的是对象的内容是否相等。 - 引用数据类型:
equals
默认比较的是地址是否相等,当重写了equals
方法后比较的是对象的内容是否相同,==
比较的是所指向的对象的地址。
// Object 中的默认equals()
public boolean equalsequals(Object obj) {
return (this == obj);
}
Object
的equals
比较的是对象的地址是否相同,String
重写equals
比较的是对象的地址上的值是否相等。
// 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;
}
final, finally, finalize 的区别
final
final
修饰的类不能被继承(String
类)修饰的类中的方法不能被重写。final
修饰的变量为常量只能赋值一次
finally
- 除非上面的代码抛出异常,
finally
中的代码一定会执行,即使上面有return
语句
try{
}catch(Exception e){
}finally{
// 代码一定会执行
}
finalize
Object
的protected
方法,子类可以覆盖该方法以实现资源清理工作,GC
在回收对象之前调用该方法。
泛型
- 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
// 泛型方法
private <T> T dealObject(T t) {
return t;
}
// 类型通配符
private void addArray(List<?> list) {
logger.info(String.valueOf(list.get(0)));
}
// 泛型类
public class ResultInfo<T> {
private T data;
private String code;
private boolean success;
// ..get、set()
}
抽象类和接口有什么区别
- 接口中没有构造方式。接口中的方法必须是抽象的,接口中除了static、final变量,不能有其他变量。接口支持多继承(一个类可以实现多个接口)。
- 抽象类可以有构造方法,接口中不能有构造方法。抽象类中可以有普通成员变量,接口中没有普通成员变量。抽象类中可以包含静态方法,接口中不能包含静态方法。一个类可以实现多个接口,但只能继承一个抽象类。接口可以被多重实现,抽象类只能被单一继承。如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法。
BIO、NIO、AIO 有什么区别
String,Stringbuffer,StringBuilder的区别
String
:字符串常量,把数据存放在了常量池中。StringBuilder
:适用于单线程下在字符缓冲区进行大量操作的情况。StringBuffer
:适用多线程下在字符缓冲区进行大量操作的情况。
JAVA中的几种基本数据类型是什么,各自占用多少字节呢
Comparator与Comparable
Comparable
是排序接口,若一个类实现了Comparable
接口,就意味着“该类支持排序”。而Comparator
是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
@FunctionalInterface
public interface Comparator<T> {}
public interface Comparable<T> {}
String类能被继承吗
- 直接上源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {}
- 用
final
关键字修饰的类。
说说Java中多态的实现原理
- 多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。
- 举个例子:工厂模式一个工厂可以拿到具体的不同的工厂对象。
Java泛型和类型擦除
- 泛型类
public class Test<T> {
T t;
}
- 泛型方法
public <T> T getObject(T t) {
return t;
}
- 泛型接口
public interface List<E> extends Collection<E> {}
- 泛型存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
说说反射的用途及实现原理,Java获取反射的三种方法
- 动态地发现和绑定类、方法、字段,以及所有其他的由于有所产生的的元素。通过反射,能够在需要时完成创建实例、调用方法和访问字段的工作。
- 反射的实现
@Test
public void t1() {
try {
// 使用Class类的fornName静态方法获得类的对象
Class clazz = Class.forName("clazz.reflection.ReflectionClass");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method x : declaredMethods) {
System.out.println(x);
}
// newInstance()和 new 有相同的功能,但是newInstance实现动态加载类,newInstance通过调用无参的构造方法
// newInstance()分解为两个步骤,先加载某个类,然后进行实例化。
ReflectionClass reflectionClass = (ReflectionClass) clazz.newInstance();
reflectionClass.show();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
@Test
public void t2() {
ReflectionClass reflectionClass = new ReflectionClass();
// getClass方法获得这个类的对象
Class<? extends ReflectionClass> aClass = reflectionClass.getClass();
Method[] declaredMethods = aClass.getDeclaredMethods();
Stream.of(declaredMethods).forEach(System.out::println);
}
@Test
public void t3() {
// 直接使用.class方法,他会自动去匹配
Class clazz = ReflectionClass.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
Stream.of(declaredMethods).forEach(System.out::println);
}
Java中IO流
类的实例化顺序
- 父类静态代码块
- 子类静态代码块
- 父初始化块
- 父构造方法
- 子初始化块
- 子构造方法
Java创建对象有几种方式
@Test
public void createObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
User user = new User();
Object user1 = Class.forName("entity.User").newInstance();
User user2 = User.class.newInstance();
logger.info("{} {} {}", user, user1, user2);
}
- 反序列化
- 调用
clone
方法
notify()和 notifyAll()有什么区别?
notify()
方法(只随机唤醒一个wait
线程),notifyAll()
方法(唤醒所有wait
线程)
Java的异常
- 图片来自:http://c.biancheng.net/view/6635.html
String s = "test"的创建过程
- 先在字符串常量池中寻找是否存在
test
的常量,如果存在则直接将常量池中的地址指向s
。 - 如果不存在,则在常量池中新建一个
test
并放入常量池里面,然后再返回该地址。
String s = new String(“test”)
- 先在字符串常量池中寻找是否存在
test
的常量 - 有的话在堆中复制一个该字符串,并且将堆中的引用指向
s
。创建一个对象。 - 没有的话,先在字符串常量池中先创建一个字符串为
test
的常量,然后再复制到堆里面,最后将堆所在的地址指向s
。总共创建两个对象。
Class.forName和ClassLoader的区别
-
Class.forName
加载并初始化了一个类。 -
ClassLoader
仅加载了类。 -
Class.forName
:中调用ClassLoader
的方法。
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
JDK动态代理与cglib实现的区别
JDK
动态代理是面向接口的;CGLib
动态代理是通过字节码底层继承代理类来实现,如果被代理类被 final 关键字所修饰,则无法被代理。
jdk
动态代理
- 定义一个接口
- 编写接口实现类
- 编写实现
InvocationHandler
接口的类,代理类的方法调用会被转发到该类的invoke()
cglib
- 实现一个
MethodInterceptor
,方法调用被转发到该类的intercept()
- 使用
Enhancer
获取代理对象,并调用对应的方法
自定义注解的场景及实现
-
可以结合
Spring Aop
等使用。 -
详见博客:https://blog.csdn.net/qq_37248504/article/details/102926592
说说你熟悉的设计模式
-
详细内容见博客:https://blog.csdn.net/qq_37248504/article/details/117753021
-
工厂模式:实现解耦,将对象的创建和使用分开,多态的充分体现。
-
单例模式:需要频繁实例化然后销毁的对象,创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
-
策略模式:形成多种决策,优化代码。
-
代理模式:找到中介租房子。
-
适配器模式:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
抽象工厂和工厂方法模式的区别
- 工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的。
什么是值传递和引用传递
- 值传递:形参是实参的拷贝,改变形参的值并不会影响外部实参的值。
- 引用传递:传递的是对象的引用,改变引用的对象,之前的对象也会改变。
可以在static环境中访问非static变量吗?
- 不可以,因为
static
变量是属于类的,在类加载的时候就被初始化了,这时候非静态变量并没有加载,故非静态变量不能访问。
Java支持多继承么,为什么
- 类只支持单继承,而接口可以实现多继承。
用最有效率的方法计算2乘以8?
int a = 2<<3;
构造器是否可被重写?
Constructor
不能被继承, 所以不能被override
. 每一个类必须有自己的构造函数, 负责构造自己这部分的构造。子类不会覆盖父类的构造函数, 相反必须负责在一开始调用父类的构造函数。
char型变量中能不能存贮一个中文汉字,为什么?
- 一个
char
类型占2个字节(16比特),所以放一个中文是没问题的。 char
类型可以存储一个中文汉字,因为Java
中使用的编码是Unicode
。
实现对象克隆
- 实现
Cloneable
接口,将clone()
方法重写为public
。 - 浅克隆:克隆对象自身引用的地址
- 深克隆:克隆对象自身以及对象所包含的引用类型对象的引用地址
public class Student implements Cloneable {
private String name;
private String sno;
// set、get...
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
hashCode的作用是什么?
public native int hashCode();
hashCode()
的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
写出几种单例模式实现,懒汉模式和饿汉模式区别
泛型的存在是用来解决什么问题
- 在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率,避免在运行时出现
ClassCastException
什么是序列化,怎么序列化,反序列
- Java 序列化就是指将对象转换为字节序列的过程,而反序列化则是只将字节序列转换成目标对象的过程。
- 通过序列化永久性保存对象,保存对象的字节序列到本地文件或者数据库中;
- 通过序列化以字节流的形式使对象在网络中进行传递和接收;
- 通过序列化在进程间传递对象;
@Test
public void testTwo() throws IOException, ClassNotFoundException {
//序列化
FileOutputStream fileOutputStream = new FileOutputStream("object.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
User user1 = new User(1, "123456", "male");
objectOutputStream.writeObject(user1);
objectOutputStream.flush();
objectOutputStream.close();
//反序列化
FileInputStream fileInputStream = new FileInputStream("object.txt");
ObjectInputStream ois = new ObjectInputStream(fileInputStream);
User user2 = (User) ois.readObject();
logger.info(user2.getId() + " " + user2.getName() + " " + user2.getAddress());
}
java8的新特性。
简述一下面向对象的”六原则一法则”
- 单一职责原则:一个类只做一件事情
- 开闭原则:对修改关闭,对扩展开放。
- 依赖倒转:参数、方法返回类型等尽可能使用抽象类,抽象类型可以被它的任何一个子类型所替代。
- 里氏替换:任何时候都可以用子类型替换掉父类型,子类一定是增加父类的能力而不是减少父类的能力,因为子类比父类的能力更多。
- 接口隔离:接口要小而专,绝不能大而全。
- 合成聚合复用:优先使用聚合或合成关系复用代码。
- 迪米特法则:最少知识原则,一个对象应当对其他对象有尽可能少的了解。
switch作用类型
char, byte, short, int, Character, Byte, Short, Integer, String, or an enum
同步和异步有什么区别?
-
同步:同步是指一个进程在执行某个请求的时候,如果该请求需要一段时间才能返回信息,那么这个进程会一直等待下去,直到收到返回信息才继续执行下去。
-
异步:异步是指进程不需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态,当有信息返回的时候会通知进程进行处理,这样就可以提高执行的效率了
什么是serialVersionUID
serialVersionUID
适用于java序列化机制。简单来说,JAVA
序列化的机制是通过 判断类的serialVersionUID
来验证的版本一致的。在进行反序列化时,JVM
会把传来的字节流中的serialVersionUID
于本地相应实体类的serialVersionUID
进行比较。如果相同说明是一致的,可以进行反序列化,否则会出现反序列化版本一致的异常,即是InvalidCastException
。
Java 中,DOM 和SAX 解析器有什么不同?
Java四大引用
作用
-
灵活的控制对象的生命周期
-
提高对象的回收机率
类型
- 强引用:
gc
永不回收强引用的对象, 即使jvm
出现内存溢出错误,使程序停止,也不会回收对象来提高内存。 - 软引用:当内存不足,
gc
对软引用对象进行回收。 - 弱引用:只要被
gc
发现弱引用,不管内存够不够,直接回收。 - 虚引用:虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。
@Test
public void test3() {
// 强引用
String str = "张三";
// 软引用
SoftReference<String> stringSoftReference = new SoftReference<>(str);
// 弱引用
WeakReference<String> weakReference = new WeakReference<>(str);
// 虚引用
ReferenceQueue<String> queue = new ReferenceQueue<String>();
PhantomReference<String> phantomReference = new PhantomReference<>(str, queue);
}
Java内存屏障
- 内存屏障是让一个
CPU
处理单元中的内存状态对其它处理单元可见的一项技术。
作用
- 阻止屏障两侧的指令重排序
- 强制把写缓冲区/高速缓存中的脏数据等写回主内存,让缓存中相应的数据失效。
类型
- 内存屏障影响的是同一个线程内的代码的执行顺序。
- LoadLoad 屏障
- LoadStore屏障
- StoreStore屏障
- StoreLoad屏障
JVM模块
-
堆:包含实例化对象及数组等。
-
栈:对象的应用变量在函数的栈内存分配。
-
程序计数器:是一个寄存器,可以看作是代码行号指示器,类似于实际计算机里的PC,用于指示,跳转下一条需要执行的命令。
-
本地方法栈:执行的是
Native
方法,为Native
方法服务。在JVM
规范中,没有对它的实现做具体规定。 -
方法区:用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码数据等。
-
Jvm
知识详见博客:https://blog.csdn.net/qq_37248504/article/details/119088250?spm=1001.2014.3001.5501
volatile关键字
-
volatile
变量的写会立即刷新到主存。 -
volatile
变量的读会读主存中的新值。 -
volatile
关键字就是提示JVM
:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
以上是关于# 技术栈知识点巩固——Java的主要内容,如果未能解决你的问题,请参考以下文章