-
管理Spring Bean的生命周期的注解
@PostContruct:
该注解被用来修饰唯一一个非静态的void()方法;
修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次;
在构造函数之后执行,init()方法之前执行.
@PreDestory:
被@PreDestory修饰的方法会在服务器卸载Servlet的时候运行,并且之后被服务器调用一次,类似于Servlet中的destory()方法,虽然PreDestory字面意思是在destory之前运行,但是被@PreDestory修饰的方法会在destory方法运行之后运行,在Servlet被彻底卸载之前,PreDestory里的Destory指的是Servlet的销毁,而不是destory()方法。
-
Spring AOP的实现方式
JDK动态代理,是Java提供的动态代理技术,可以在运行时创建接口的代理实例。
CGLib动态代理,采用底层的字节码技术,在运行时创建子类代理的实例。 -
JVM内存配置参数:
-Xmx:最大堆大小
-Xms:初始堆大小(最小堆内存)
-Xmn:年轻代大小
-XXSurvivorRatio:年轻代中Eden区与Survivor区的大小比值(例:XXSurvivorRatio=3表示Eden:Survivor=3)
jdk自带调优工具:jvisualvm ->在jdk安装路径bin下面。
java虚拟机内存模型参考:https://zhuanlan.zhihu.com/p/98337005 -
int型的比较Long也一样
-
Integer&Long&Float&Double
Integer (4字节32位)与 Long(8字节64位)
通过Integer a = 12;Long b = 12l;构造时会调用valueOf方法
且整型的数据默认使用int如果用Long则必须通过Long a = 12l的方式而不能使用L a = 12;
Float(4字节32位)Double(8字节64位)
浮点型的数据默认使用Double,通过Double a = 12.0的方式构造调用valueOf方法
浮点型数据默认使用Double若使用Float为防止精度不够需要使用Float a = 12.0f的方式。 -
Set
LinkedHashSet继承于HashSet、又基于 LinkedHashMap 来实现(按添加顺序排序);
TreeSet使用二叉树的原理对新 add()的对象按照指定的顺序排序(升序、降序),每增加一个对象都会进行排序,将对象插入的二叉树指定的位置(自然排序)。
HashSet无序不可重复; -
java相关的应用程序
javac.exe 编译将.java文件编译成.class文件
java.exe 执行编译好的.class文件
javap -c 民令 将.class文件生成可读的字节码文件
javadoc.exe 生成Java说明文档
jdb.exe Java调试器
javaprof.exe 剖析工具 -
类型比较、拆装箱问题
包装类的运算在不遇到算术运算的情况下不会自动拆箱;
包装类的equals()方法不处理数据转型;
包装类与基本数据类型时会自动拆包比较大小; -
父子类问题
构造函数:
子类无法继承构造函数,构造函数只能被显示或隐式的调用;
显示则通过super(),super(a),super(a,b…)调用。静态代码块、非静态代码块、构造函数执行顺序:
静态代码块是用来初始化类的信息,在类被加载的时候就会被执行,且只执行一次。
非静态代码块:是用来初始化类的实例信息,在创建对象的时候就会被执行,且每创建一个对象都会被执行一次且先于构造函数执行。
执行顺序:静态代码块(类加载时被执行1次)>非静态代码块(new 对象时执行)>构造方法 -
Synchronized和ThreadLocal
ThreadLocal类用于创建一个线程本地变量在Thread中有一个成员变量ThreadLocals,该变量的类型是ThreadLocalMap,也就是一个Map,它的键是threadLocal,值就是变量的副本,ThreadLocal为每一个使用该变量的线程都提供了一个变量值的副本,每一个线程都可以独立地改变自己的副本,是线程隔离的。通过ThreadLocal的get()方法可以获取该线程变量的本地副本,在get方法之前要先set,否则就要重写initialValue()方法。ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。Synchronized和ThreadLocal的区别:
1、对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式.
2、Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
3、Synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。一句话理解ThreadLocal,向ThreadLocal里面存东西就是向它里面的Map存东西的,然后ThreadLocal把这个Map挂到当前的线程底下,这样Map就只属于这个线程了。
使用场景:
ThreadLocal:在调⽤ API 接⼝的时候传递了⼀些公共参数,这些公共参数携带了⼀些设备信息(是安卓还是 ios),服务端接⼝根据不同的信息组装不同的格式数据返回给客户端。
Synchronized:
修饰普通方法:对当前对象实例加锁,调用该方法需要获得当前对象实例的锁
修饰静态方法:对当前类加锁,会对该类的所有实例加锁,因为静态方法不属于任何一个实例对 象,是属于类成员。所以当线程A访问调用一个实例对象的synchronized方法,线程B调用这个实例对象的 静态synchronized方法是允许的
修饰代码块:对指定的对象加锁,可以指定变量,也可以指定类,指定变量是需要获得该变量对应类的实例锁,由于基本类型不是对象,所以synchronized不可以修饰基本类型变量;指定类是需要获得当前类加锁 -
常见的ASCAII码
数字0-9 从48开始
大写字母A-Z 从65开始
小写字母a-z 从97开始 -
Java表达式转型规则由低到高转换:
1、所有的byte,short,char型的值将被提升为int型;
2、如果有一个操作数是long型,计算结果是long型;
3、如果有一个操作数是float型,计算结果是float型;
4、如果有一个操作数是double型,计算结果是double型;
5、被fianl修饰的变量不会自动改变类型,当2个final修饰相操作时,结果会根据左边变量的类型而转化。
1.被final修饰的为byte,short,char,int中的任何一种,则运算之后,得到的类型可以是byte、short、char、int、long、float、double中的任何一种都不会出错;(前提是计算结果不能超出左边的取值范围,比如两个a都是char但是相加结果是194,超出了byte范围,所以结果不能是byte)2.如果运算中有被final long 或者 final float 或者 final double修饰,则结果必须为同级别或者高一级别,eg:
-
二维数组创建规范
二维数组创建时需要注意等式左边要求不严格,但是等式右边必需声明行的大小。
Object类的方法:
modifer and Type | Method and Description |
---|---|
protected Object | clone 创建并返回此对象的副本 |
boolean | equals(Object obj) 提示其他对象是否等于此(默认为==) |
protectedn void | finalize() 当垃圾收集确定不再有对该对象的引用时垃圾收集器在对象上调用该对象。 |
类<?> | getClass() 返回此Object的运行时类。 |
int | hashCode() 返回对象的哈希码值。 |
void | notify() 唤醒正在等待对象监视器的单个对象。 |
void | notifyAll() 唤醒正在等待对象监视器的所有对象。 |
String | toString() 返回对象的字符串表达式。 |
void | wait() 导致当前线程等待,直到另外一个线程调用该对象的notify()方法或notifyAll()方法。wait(long timeout)指定时间(毫秒)过去会被唤醒。wait(long timeout,int nacos) 毫秒+毫微秒 |
-
多态注意事项
编译时看左边,运行时看右边。
如果A类是B类的父类而B在实现A类的a方法得基础上扩展了b方法;此时按照下述写法会产生编译时异常。
A a = new A ();
B b = new B ();
a.a();
b.a();
b.b(); //此出会出现编译出错 -
序列化
静态变量无法被序列化,改变了静态变量的值之后将对象进行序列化传输之后再反序列化后静态变量会变成初始值。
例如:
public class DataObject implements Serializable{
private static int i=0;
private String word=" ";
public void setWord(String word){
this.word=word;
}
public void setI(int i){
Data0bject.i=i;
}
}
创建一个如下方式的DataObject:
DataObject object=new Data0bject ( );
object.setWord(“123”);
object.setI(2);
将此对象序列化为文件,并在另外一个JVM中读取文件,进行反序列化,请问此时读出的Data0bject对象中的word和i的值分别为:
“123”, 0 -
类方法和实例方法
在类方法中调用本类的类方法可直接调用。 实例方法也叫做对象方法。
类方法是属于整个类的,而实例方法是属于类的某个对象的。
由于类方法是属于整个类的,并不属于类的哪个对象,所以类方法的方法体中不能有与类的对象有关的内容。即类方法体有如下限制:
(1) 类方法中不能引用对象变量;
(2) 类方法中不能调用类的对象方法;
(3) 在类方法中不能使用super、this关键字。
(4)类方法不能被覆盖。
如果违反这些限制,就会导致程序编译错误。
与类方法相比,对象方法几乎没有什么限制:
(1) 对象方法中可以引用对象变量,也可以引用类变量;
(2) 对象方法中可以调用类方法;
(3) 对象方法中可以使用super、this关键字。
-
switch支持的数据类型
以java8为准,支持10种数据类型分别是byte、short、char、int四种基本数据类型以及Byte、Short、Char、Integer四个包装类和String、Enum两个特殊类。但是最终其实还是仅支持int型数据,其中byte、short、char会向上转型Byte、Short、Char、Integer会自动拆箱。String实际上是比较的HashCode,Enum实际上比较的是枚举值的顺序。 -
抽象类
特点:
1.抽象类中可以构造方法
2.抽象类中可以存在普通属性,方法,静态属性和方法。
3.抽象类中可以存在抽象方法。
4.如果一个类中有一个抽象方法,那么当前类一定是抽象类;抽象类中不一定有抽象方法。
5.抽象类中的抽象方法,需要有子类实现,如果子类不实现,则子类也需要定义为抽象的。
6,抽象类不能被实例化,抽象类和抽象方法必须被abstract修饰关键字使用注意:
抽象类中的抽象方法(其前有abstract修饰)不能用private、static、synchronized、native访问修饰符 修饰。 -
接口
1.在接口中只有方法的声明,没有方法体。
2.在接口中只有常量,因为定义的变量,在编译的时候都会默认加上public static final
3.在接口中的方法,永远都被public来修饰。
4.接口中没有构造方法,也不能实例化接口的对象。(所以接口不能继承类)
5.接口可以实现多继承
6.接口中定义的方法都需要有实现类来实现,如果实现类不能实现接口中的所有方法则实现类定义为抽象类。
7,接口可以继承接口,用extends -
方法中定义的局部变量的创建时间
当代码执行到该变量被赋值的代码时才被创建,此时jvm才会为之分配内存空间。 -
Java中可以将布尔值与整数进行比较吗 ?
boolean 类型不能转换成任何其它数据类型。 -
int与Integer比较时会自动拆包比较值的大小
-
ServletContext中的属性(Attribute)和参数(Parameter)
其中初始化参数是配置信息,属性是保存在上下文中的键值对。前者通过getInitParameter()方法获取,后者通过getAttribute()获取。 -
数组之间的比较
数组也是对象并且数组本身并没有重写equals方法,如果直接通过arry1.equals(arry2)的方式进行比较相当于arry1 == arry2 。如果要对两个数组中存储的每一个数据进行对比的话需要用Arrys.equals(arry1,arry2)。 -
Math.ceil()与Math.floor()
ceil:天花板数,向上取整。
floor:地板数,向下取整