(1). Java基础知识

java面向对象的基础特征:
1.抽象:指从一些类中抽象出他们共有的特征构造类的过程,包括数据抽象和行为抽象;
2.封装:是将数据和操作数据的方法绑定起来,对数据的访问只通过已经定义的接口;
3.继承:是从已有类中得到继承信息创建新类的过程,被继承的类称为父类,得到继承信息的类叫子类;
4.多态:允许不同子类型的对象对同一消息的做出不同的反应。多态的前提是:继承关系、方法的重写、父类的引用指向子类的对象。

java里面的变量类型
1.成员变量:定义在类里面的变量
2.静态变量(也称类变量):使用static关键字修饰的变量;
3.局部变量:定义在方法里的变量;
4.final变量:相当于常量;
5.transient变量:该关键字修饰的变量不会被序列化;
6.volatile变量:用在多线程,用来变量同步。

对象为什么要序列化
1.序列化是用来将对象转化为字节流以便用来存储或在网络上传输,为了解决对象流在读写上面的问题,是对象永久化的一种机制;
2.一般的对象随着程序的运行而产生,随着程序的停止而消失,但是如果想让这些对象保留下来,当程序下次运行的时候继续使用,或者别的程序的调用,则需要使用序列化进行保存;
3.只有序列化的对象才可以存储在存储设备上;
4.当父类已经实现了序列化,那么子类自动实现序列化,不需要显示的实现serializable接口;反过来,如果父类没有序列化,那么子类的序列化会丢失父类的信息;
5.当一个对象的实例变量对另一个对象进行了引用,那么这个对象序列化时,也会使引用的对象序列化;

总结:序列化的最主要目的是为了传递和保存对象时,保证对象的完整性和可传递性

0.static关键字
static关键字的注意事项
功能:
修饰属性.方法,块,内部类
1、静态元素在类加载的时候就被初始化,创建的很早,那时还没有创建对象
2、静态元素存储在静态元素区中,每一个类都有自己的一个单独的区域,与别的类不冲突
3、静态元素区不能被GC管理,可以简单的认为静态元素常驻内存
4、静态元素只加载一次,供全部的类对象和类本身共享
5、可以理解为静态元素与对象没有关系,它属于类
6、由于静态元素在加载的时候可能还没有创建对象,我们可以直接通过类名直接调用静态元素
7、静态元素可以直接访问静态元素。
8、非静态元素可以直接方法静态元素,但是静态元素不能直接方法非静态元素
9、静态元素中不可以使用this,super关键字
//
static关键字可以用来修饰属性、方法、代码块
静态元素在类加载的时候就已经被初始化
静态元素存储在方法区,一般不会被GC,默认为常驻元素;
静态元素属于类,可以通过类名直接调用;非静态元素可以通过类的实例化来调用。

1.java中==和equals和hashCode的区别

答:==:常量比较比较的是数值,对象使用比较的是地址;
equals:不能作用于基本数据类型,如果没有对equals进行重写,则比较的是 引用类所指向的地址。如果重写了,比较的就是对象的内容。
hashcode:Object类里的hashcode返回每个对象的地址,如果重写了equals方法就必须要重写hashCode方法,以便用户将对象插入到散列表中。equals相等的两个对象,hashCode一定相等,equals不相等的两个对象,却并不能证明他们的hashCode不相等。equals方法不相等的两个对象,hashCode有可能相等,在每个覆盖了equals方法的类中,也必须覆盖hashCode方法,如果不这样做的话,就会违反Object.hashCode的通用约定。从而导致该类无法结合所有基于散列的集合一起正常运作。

2.int与integer的区别

(1)int是常量,Integer是封装类。
(2)integer必须实例化才可以使用,而int不需要实例化;
(3)Integer实际上实例化是产生一个对对象的引用,而int是直接存储的数值;
(4)Integer的默认值是null,而int的默认值是0;

3.接口和抽象类的区别
抽象类从一些类中抽取出他们共有的一些属性(例如某些相同的成员变量、属性相同(修饰符、函数名、参数类型、参数个数)的方法),接口是对一些类的行为进行抽象;
抽象类和接口都是为了设计和实现隔离;
接口可以多重实现,而抽象类不可以;
jdk1.8后接口可以用default去实现,此时接口的子类可以调用default修饰的方法;而抽象类可以实现部分方法,可以有具体方法,main方法也可以有,但是接口不可以;
抽象类中可以没有抽象方法,但是有抽象方法的一定是抽象类;
接口中的变量都是public static final修饰的,即编译就实现了初始化;
当我们对事物的本质根源进行研究是,可以使用抽象类,对事物的行为进行研究时,使用接口更方便,一个事物可以实现多种接口来实现不同的行为;
相同点:
抽象类和接口都不可以被实例化,即不可以通过new来为他分配空间;
接口和抽象类的子类都一定要实现他们全部的抽象方法,否则子类还是个抽象类。

4.能否创建一个包含可变对象的不可变对象?
不可变:final、private,深拷贝,引用修改即修改拷贝对象,
可以通过反射来调用,改变不可变对象

5.谈谈对java多态的理解
前提:有继承关系、有方法重写、父类的引用是子类的对象(person p=new superperson();)
定义:实质是一个方法的调用可以多个类响应
作用:用来消除类型之间的耦合关系
多态就是同一个接口,不同的实例去执行不同的行为;
多态的优点:
1.消除类型之间的耦合关系,接口性;
2.灵活性,简化性;
3.可扩充性,可替换性;

6.String、StringBuffer、StringBuilder区别
String:final修饰,线程安全。不可变
StringBuilder/StringBuffer继承abstractStringBuilder类,可变,
StringBuffer由同步锁修饰,线程安全、StringBuilder则不安全
不是多线程的情况下,StringBuilder更快

7.泛型中extends和super的区别
分别为上下界通配符

8.进程和线程的区别
进程:进程是资源分配的最小单位;每一个进程系统就会为该进程分配独立的地址空间;进程之间的并发不会对相互之间产生影响;
线程:线程是cpu执行的最小单位,是进程中的执行流,;一个进程中的线程共享该进程的资源和空间;线程间并发时,会相互影响;

9.final,finally,finalize的区别
final:final不可与adstract共同修饰,final修饰不可改
finally:在异常处理里面,try出异常跳转到catch,但是不管try出不出异常,都会最终执行finally
finalize:是一个方法名,在垃圾回收前必须用,清扫这个对象之前被引用的部分

10.序列化的方式
序列化转换成字节流为了更好的传输。

序列化需要:
所需类:ObjectInputStream和ObjectOutputStream
方法: readObject()和writeObject();

序列化方式一: 实现Serializable接口(隐式序列化)
通过实现Serializable接口,这种是隐式序列化(不需要手动),这种是最简单的序列化方式,会自动序列化所有非static和 transient关键字修饰的成员变量。

序列化方式二:实现Externalizable接口。(显式序列化)
Externalizable接口继承自Serializable, 我们在实现该接口时,必须实现writeExternal()和readExternal()方法,而且只能通过手动进行序列化,并且两个方法是自动调用的,因此,这个序列化过程是可控的,可以自己选择哪些部分序列化

序列化方式三:实现Serializable接口+添加writeObject()和readObject()方法。(显+隐序列化)
如果想将方式一和方式二的优点都用到的话,可以采用方式三, 先实现Serializable接口,并且添加writeObject()和readObject()方法。注意这里是添加,不是重写或者覆盖。但是添加的这两个方法必须有相应的格式。

1,方法必须要被private修饰 ----->才能被调用
2,第一行调用默认的defaultRead/WriteObject(); ----->隐式序列化非static和transient
3,调用read/writeObject()将获得的值赋给相应的值 --->显式序列化

11.string 转换成 integer的方式及原理
parseInt(String s)--内部调用parseInt(s,10)(默认为10进制)
正常判断null,进制范围,length等
判断第一个字符是否是符号位
循环遍历确定每个字符的十进制值
通过*= 和-= 进行计算拼接
判断是否为负值 返回结果。

12.静态属性和静态方法是否可以被继承?是否可以被重写?以及原因?
可以继承,java里面的所有方法都可以继承,包括私有方法(但不可见)和静态方法;
不可以重写:重写是在动态时绑定的,静态元素是在编译时绑定的。如果父类、子类方法名相同,则隐藏父类静态方法;重写只能重写实例方法。

13.成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用
成员内部类:一个类内部定义了一个非静态类,可以有非静态属性和非静态方法,也可以有(static final)修饰的静态常量。
总结:1、成员内部类可以由public protected default private修饰

   2、成员内部类是依赖于外部类的对象而存在的,在创建成员内部类的实例时,外部类的实例必须已经存在。

   3、成员内部类可以包含哪些内容

   1)匿名代码块

   2)非静态属性

   3)非静态方法

注意:成员内部类中不能有静态属性和方法但可以有静态常量(即用static final修饰的属性),因为在类加载时会初始化static修饰的内容,而成员内部类必须依赖于内部类对象,即成员内部类要在外部类加载之后加载,所以不能包含静态的变量和方法。使用final修饰的静态变量类加载时会自动初始化其值,将其作为一个常量,所以可以出现在内部类中。

   4、外部类访问内部类

   外部类可以通过创建成员内部类实例来访问成员内部类中的属性和方法

   5、成员内部类访问外部类

   成员内部类可以直接访问外部类的所有属性和方法

注意: 如果成员内部类B与外部类A包含同名的成员,那么在类B中, this.v表示类B的成员, A.this.v表示类A的成员。

   6、创建内部类实例的方法

   1)在外部类中创建:内部类名 name = this.new 内部类名();

   2)在非外部类中创建:外部类名.内部类名 name = new 外部类名().new 内部类名();
静态内部类:一个类内部定义了一个静态内部类,应用有HashMap里的Entry,HashMap内部维护Entry数组用了存放元素,但是Entry对使用者是透明的。像这种和外部类关系密切的,且不依赖外部类实例的,都可以使用静态内部类。
总结:1、静态内部类中可以写哪些内容

   1)匿名代码块

   2)静态代码块

   3)静态变量和非静态变量

   4)静态方法和非静态方法

注意:不能在静态内部类中写抽象方法

   2、外部类如何调用静态内部类中的属性和方法

   1)外部类可以通过创建静态内部类实例的方法来调用静态内部类的非静态属性和方法

   2)外部类可以直接通过“ 外部类.内部类.属性(方法)” 的方式直接调用静态内部类中的静态属性和方法

   3、静态内部类如何调用外部类的属性和方法 

   1)静态内部类可以直接调用外部类的静态属性和方法

   2)静态内部类可以通过创建外部类实例的方法调用外部类的非静态属性和方法

   4、如何创建静态内部类实例

   1)在非外部类中:外部类名.内部类名 name = new 外部类名.内部类名();

   2)在外部类中:内部类名 name = new 内部类名();

局部内部类:定义在方法中的类,如果一个类只在某个方法中使用,则可以考虑使用局部类。

匿名内部类:匿名内部类是没有访问修饰符的。new 匿名内部类,这个类首先是要存在的。当所在方法的形参需要被匿名内部类使用,那么这个形参就必须final。匿名内部类没有明面上的构造方法,编译器会自动生成一个引用外部类的构造法。匿名内部类使用广泛,比如我们常用的绑定监听的时候

14.讲一下常见编码方式?
ISO8859-1,GBK/GB2312,Unicode,UTF,ASCII

15.如何格式化日期?
package date2;

import java.util.Date;
import java.text.SimpleDateFormat;

public class TestDate {

public static void main(String[] args) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); //制定输出格式
    Date d = new Date();
    String str = sdf.format(d); //将日期转换为字符串且格式按照之前制定的
    System.out.println("当前时间通过 yyyy-MM-dd HH:mm:ss SSS 格式化后的输出: "+str);
    //下面同理
    SimpleDateFormat sdf1 =new SimpleDateFormat("yyyy-MM-dd" );
    Date d2 = new Date();
    String str2 = sdf1.format(d2);
    System.out.println("当前时间通过 yyyy-MM-dd 格式化后的输出: "+str2);
}

}

16.Java的异常体系
Error:不可处理错误,只能退出JVM
Exception:可处理的错误,两种方式可以解决:try,throws
图片说明

17.什么是异常链
把捕获的异常包装成一个新的异常,在新的异常中添加对新的异常的引用,再把新异常抛出,就像是链式反应一样,这种就叫异常链。

18.throw和throws的区别
throws:用在方法函数头部,表示一种状态可能有异常抛出,并且可能抛出多个异常
throw:用在方法体里面,表示抛出这个动作每次只抛出一个异常。

19.反射的原理,反射创建类实例的三种方式是什么。
所谓的反射机制就是java语言在运行时拥有一项自观的能力。在程序运行的过程中。对于任何一个类,都可以通过反射知道这个类的属性和方法,对于任何一个对象,都可以调用这个对象的属性和方法。这种动态获取或者调用类和对象的方法的过程叫做反射;
Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method;其中class代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组 成部分。

反射创建类实例的三种方式:

//创建Class对象的方式一:(对象.getClass()),获取person类中的字节码文件
Class<testclass> class = Class.forName("com.zkw.TestClass");</testclass>

//创建Class对象的方式二:(类.class:需要输入一个明确的类,任意一个类型都有一个静态的class属性)
Class<testclass> class = TestClass.class;</testclass>

//创建Class对象的方式三:(forName():传入时只需要以字符串的方式传入即可)
//通过Class类的一个forName(String className)静态方法返回一个Class对象,className必须是全路径名称;
//Class.forName()有异常:ClassNotFoundException
TestClass tc = new TestClass();
Class<testclass> class = tc.getClass();</testclass>

注意:在开发中一般使用第三种方法,因为第三种接收的是一个字符串路径,将来可以通过配置文件获取,通用性好;

// 通过Class对象创建类实例
TestClass testClass = class.newInstance();

20.java当中的四种引用
(1)强引用:是指创建一个对象并把这个对象赋给一个引用变量。 强引用有引用变量指向时永远不会被垃圾回收,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。
(2)软引用:如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。
SoftReference的特点是它的一个实例保存对一个Java对象的软引用, 该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对 这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之 后,get()方法将返回null。
(3)弱引用(WeakReference):弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。
(4)虚引用(PhantomReference):虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

21.深拷贝和浅拷贝的区别是什么?
浅拷贝:只复制指向对象的指针,并不是复制对象本身,新旧对象还是共享一块内存,两个对象之间是联动的。浅拷贝可以通过实现clonable接口实现;
深拷贝:创造了一个一模一样的对象,但是新对象和旧对象没有共享内存,互相之间的修改也不会受到影响。可以通过对每一层进行浅拷贝实现,也可以对对象进行序列化实现。

22.什么是编译器常量?使用它有什么风险?
编译期常量指的就是程序在编译时就能确定这个常量的具体值
非编译期常量就是程序在运行时才能确定常量的值,因此也称为运行时常量
定义上来说,声明为final类型的基本类型或String类型并直接赋值(非运算)的变量就是编译期常量,即:
//编译时常量
final int i = 4;
final String str = "dasd";
// 非编译期常量
final String str1 = new String("dasd");
Random rand = new Random(47);
风险:这种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时常量,但是这个值后面被其他人改变了,部署了一个新的jar,但是你的客户端仍然在使用老的值。为了避免这种情况,当你在更新依赖 JAR 文件时,确保重新编译你的程序。这里的更新JAR文件,重新编译程序是为了更新你使用的编译期常量的值!

23.你对String对象的intern()熟悉么?
使用intern方法,主动将串池中还没有的字符串对象放入串池,如果有则不会放入。会把串池中的对象返回。
在1.8中,使用intern方法将这个字符串对象尝试放入串池,如果有则不会放入,如果没有会放入串池(指向这个对象,即是同一个对象),并将串池对象返回。
String a="abc";
String b=new String("abc");
a==b.intern();//true;

24.a=a+b与a+=b有什么区别吗?
如果a与b数据类型不一样,则涉及到了类型转换,+=会自动类型转换。

25.静态代理和动态代理的区别,什么场景使用?

26.Java中实现多态的机制是什么?
继承、重写、父类的引用指向子类的对象

27.说说你对Java反射的理解
反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。
反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

Java 反射主要提供以下功能:

在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
在运行时调用任意一个对象的方法
重点:是运行时而不是编译时

28.说说你对Java注解的理解
(1)生成文档相关的注解

@author 标明开发该类模块的作者,多个作者之间使用“,”分割
@version 标明该类模块的版本
@see 参考转向,也就是相关主题
@since 从哪个版本开始增加的
@param 对方法中某参数的说明,如果没有参数就不能写
@return 对方法返回值的说明,如果方法的返回值类型是void就不能写
@exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常
(2)编译时检查注解

@Override: 限定重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构
危险或存在更好的选择
@SuppressWarnings: 抑制编译器警告
(3)自定义注解

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

String value() default "";

}

29.说说你对依赖注入的理解
依赖注入
上面将依赖在构造函数中直接初始化是一种 Hard init 方式,弊端在于两个类不够独立,不方便测试。我们还有另外一种 Init 方式,如下:

public class Human {
...
Father father;
...
public Human(Father father) {
this.father = father;
}
}
上面代码中,我们将 father 对象作为构造函数的一个参数传入。在调用 Human 的构造方法之前外部就已经初始化好了 Father 对象。像这种非自己主动初始化依赖,而通过外部来传入依赖的方式,我们就称为依赖注入。
现在我们发现上面 1 中存在的两个问题都很好解决了,简单的说依赖注入主要有两个好处:
(1). 解耦,将依赖之间解耦。
(2). 因为已经解耦,所以方便做单元测试.

30.说一下泛型原理,并举例说明
泛型是Java 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
Java泛型被引入的好处是安全简单。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
泛型在使用中还有一些规则和限制:
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如。习惯上成为“有界类型”。
5、泛型的参数类型还可以是通配符类型。

31.Java中String的了解

32.String为什么要设计成不可变的?
1、便于实现字符串池(String pool)
2、使多线程安全
3、避免安全问题
4、加快字符串处理速度

33.Object类的equal和hashCode方法重写,为什么?
equals在object里面是默认的比较地址,hashcode是用来计算存储地址的,如果equals都一致的,hashcode也一定一致。

34.内部类
静态内部类:不可以访问外部的非静态资源,可以有public static abstract class demo
成员内部类:可以访问所有的外部资源(但本身内部不可以有静态属性,因为自己本身要通过外部类的实例化实现)
局部内部类:是作用在一个方法或作用域里面的内部类,只可以在该方法和作用域里使用,不可被访问修饰符和static修饰,只能访问final变量和形参;
匿名内部类:没有构造器,没有静态资源,无法被访问修饰符、static修饰,只能创建匿名内部类的一个实例,创建的时候一定是在new后面。

35.重写与重载
重载:方法名一样,返回类型和参数类型不一样;
重写:方法名一样,返回类型和参数类型也一样;

36.private/protected/public
private:只对类内部开放
protected:只对类即子类可用;对同一个包下面的类可用
default:只对类可当前包下面的类可用;
public:对所有用户可用
图片说明