Java基础面试题
1.switch的使用
int x = 2;
int result = 0;
switch (x) {
case 1:
result = result + x;
case 2:
result = result + x * 2;
case 3:
result = result + x * 3;
}
System.out.println(result);
// 返回结果为10
// switch语句当case与值不匹配时,会跳到下一个,当匹配时,会把当前和后面所有的都执行一遍。
// 如果有break,则不继续往下执行
------------------------------------
以java8为准,switch支持10种类型 基本类型:byte char short int
对于包装类 :Byte,Short,Character,Integer String enum
switch语句可以嵌套
2.在不使用第三个参数的情况下,使两个整数(a,b)的值互换
a = a + b;
b = a - b;
a = a - b;
3.重写和重载的区别
1.方法的参数列表不同:
重载要求方法名相同,但参数列表不同;
而重写要求方法名、参数列表和返回值类型都必须与父类中的方法相同。
重写时,当方法名、参数列表相同,返回值不同会编译报错。当方法名相同,参数列表不同,无论返回值是否相同,都算新的方法
2.访问权限不能改变:
重载是一个类中可以有多个同名方法,但这些方法的参数列表必须不同;
而重写是子类继承父类并重新实现其中的方法,因此重写的方法,访问权限必须大于等于父类。
3.返回值类型可以相同也可以不同:
重载要求方法名相同,参数列表不同,可以有不同的返回值类型;
而重写要求方法名、参数列表和返回值类型都必须与父类中的方法相同。
4.抛出异常可以不同:
重载要求方法名相同,参数列表不同,可以有不同的异常声明;
而重写要求方法名、参数列表和返回值类型都必须与父类中的方法相同,因此不能抛出新的异常或者不抛出异常。
5.重载是编译时多态,而重写是运行时多态:
重载发生在编译时,编译器根据方法的参数列表决定调用哪个方法;
而重写发生在运行时,JVM根据对象的实际类型来调用相应的方法。
------------------------------------------------------------------------------------------------------------
1.重写
发生在子类和父类之间,返回值、入参、方法名都相同。重写方法的访问权限不能低于父类方法的访问权限,并且重写方法不能抛出新的或者更宽泛的异常
2.重载
发生在同类之间,名称相同,参数列表不同,可以是类型,数量,【顺序】
final、static、private修饰的方法不能被重写,不在同一个包里的类,缺省的修饰符也不能重写
4.stringbuilder、stringbuffer、String的区别
StringBuilder和StringBuffer都代表可变的字符序列,但它们在处理字符串变化时的行为存在差异。主要的区别包括:
线程安全性:StringBuffer是线程安全的,其方法用synchronized关键字进行修饰,因此在多线程环境下,同一时间只能有一个线程访问它的方法。而StringBuilder则不具备这个特性,所以它的性能更高,因为锁的获取和释放会带来开销。
可变性:String是不可变的,这意味着每次对String的操作都会生成新的对象。相比之下,StringBuilder和StringBuffer的对象能够被修改。
性能:由于StringBuilder不是线程安全的,所以在不需要进行多线程操作的情况下,它比StringBuffer具有更高的性能。
String的底层是一个final的char数组
6.低等级数据类型+高等级数据类型,会转成高等级
short num1 = 3;
num1 = num1+3; // 这行会编译错误
num1+=3;// 这行不会编译错误,【+=会自动进行类型转换】
7.退出ArrayList的foreach循环
List<String> list = Arrays.asList("1", "2", "3");
// 这种方式是没办法正常退出的
list.forEach(l ->{
System.out.println(l);
});
// 这种方式可以通过break退出
for (String s : list) {
System.out.println(s);
break;
}
8.http相应码分类
信息性响应(100-199):表示请求已成功处理,但需要进一步操作。
成功响应(200-299):表示请求已成功处理,客户端可以继续进行后续操作。
重定向响应(300-399):表示需要进行额外的操作以完成请求,例如临时重定向、永久重定向等。
客户端错误响应(400-499):表示请求有误,客户端需要修改后重新发送请求。
服务器错误响应(500-599):表示服务器在处理请求时发生错误,无法完成请求。
401:当前请求需要用户验证
403:服务器理解请求,但是拒绝执行
404:资源未找到
500:服务器错误
502:此错误响应表明服务器作为网关需要得到一个处理这个请求的响应,但是得到一个错误的响应
504:网关超时
200:成功,Web 服务器成功处理了客户端的请求。
301:永久重定向,当客户端请求一个网址的时候,Web 服务器会将当前请求重定向到另一个网址,搜索引擎会抓取重定向后网页的内容并且将旧的网址替换为重定向后的网址。
302:临时重定向,搜索引擎会抓取重定向后网页的内容而保留旧的网址,因为搜索引擎认为
重定向后的网址是暂时的。
400:客户端请求错误,多为参数不合法导致 Web 服务器验参失败。
404:未找到,Web 服务器找不到资源。
500:Web 服务器错误,服务器处理客户端请求的时候发生错误。
503:服务不可用,服务器停机。
504:网关超时。
HTTP和HTTPS的区别
1、端口不同,http用的80,https用443
2、消耗资源,https因为加解密消耗更多的CPU和内存资源
3、https通信需要证书,证书通常需要向认证机构付费购买
在HTTPS协议中,TLS协议层(Transport Layer Security)是加密的主要实现者。TLS协议层采用了非对称加密算法RSA和对称加密算法AES来保护数据传输的安全性。
9.String字符串
String str1 = "hello";
String str2 = "he" + new String("llo");
String str3 = "he" + "llo";//编译阶段会把字符串连起来
System.out.println(str1 == str2);
System.out.println(str1 == str3);
// 返回的是false 和 true
------------------------------------------------------------------------------------------------------------
String a = "a";
String b = "b";
String str1 = "a" + "b";//常量池中的对象
String str2 = a + b; //在堆上创建的新的对象
String str3 = "ab";//常量池中的对象
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//true
System.out.println(str2 == str3);//false
11.java中有几种类型的流,jdk中分别提供了对应的抽象类供继承,他们分别是哪些
字节流:InputStream和OutputStream
字符流:Reader和Writer
文件流:FileInputStream、FileOutputStream、FileReader和FileWriter
对象流:ObjectInputStream和ObjectOutputStream
12.servlet的生命周期有哪些,分别用什么方法表示
1.初始化,init方法
2.处理请求,service方法
3.销毁,destory方法
14.springboot有哪几种读取配置的方式
使用@Value注解:这是最基础的读取配置的方式,可以用来读取springboot全局配置文件中的单个配置。
通过Environment接口:利用此接口,可以动态地获取配置信息。例如,可以将yml文件的全部内容封装到Environment对象中。
使用@ConfigurationProperties注解:如果在配置类上使用此注解并指定加载配置项的前缀,就可以批量读取配置并将这些配置注入自定义类的成员变量中。需要注意的是,自定义类需要提供setter方法。
使用PropertySource注解:这种方式主要用于加载properties文件的配置,然后就可以在字段上使用@Value来获取配置。
通过命令行参数:Spring Boot也可以从命令行参数中读取配置信息。
通过操作系统环境变量:此外,Spring Boot还可以从操作系统的环境变量中读取配置信息。
15.如何在iterator遍历过程中安全删除一个对象
// 使用迭代器遍历,使用remove方法删除
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
Iterator<String> iterator = list.iterator();
int index = 0;
while (iterator.hasNext()){
String next = iterator.next();
if ("2".equals(next)){
iterator.remove();
}
index++;
}
System.out.println(list);
19.try...fatch...finally执行顺序
// finally之前,return的值会放入临时空间,如果finally中有对return中值的操作,则会刷新临时空间的值
public static void main(String[] args) throws UnsupportedEncodingException {
System.out.println(test());
}
public static int test(){
int temp = 1;
try {
System.out.println(temp);
return ++temp;
}catch (Exception e){
System.out.println(temp);
return ++temp;
}finally {
++temp;
System.out.println(temp);
}
}
// 输出的1,3
finally代码块在return中间执行,return的值会被放入临时空间,然后执行finally,如果finally中有return,则会刷新临时空间的值,方法结束后返回临时空间值
finally里的代码在try中的return之前执行
catch中return了,finally还是会执行,在return之前
finalize方法是在对象被垃圾回收器回收之前调用的
20.数据库事务传播形式:7种
PROPAGATION_REQUIRED(默认):如果当前没有事务,就新建一个事务,如果已经存在一个事务中,就加入到这个事务中。
PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,则加入该事务,如果当前不存在事务,则以非事务的方式继续运行。
PROPAGATION_MANDATORY:强制当前事务存在,如果当前不存在事务,就抛出异常。
PROPAGATION_REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。
PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,就抛出异常。
PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则创建一个新的事务。
required:必须的
mandatory:强制的
nested:嵌套的
21.数据库隔离级别
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
读未提交(READ UNCOMMITTED) | 会导致 | 会导致 | 会导致 |
读已提交(READ COMMITTED) | 会导致 | 会导致 | |
可重复读(REPEATABLE READ) | 会导致 | ||
串行化(SERIALIZABLE) |
1.脏读:读到了其他事务未提交的数据
2.不可重复读:指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况。
3.幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。
更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。
核心OB是读已提交
Mysql默认是可重复读
22.权限修饰符区分
public | protected | default | private | |
---|---|---|---|---|
同类 | 支持 | 支持 | 支持 | 支持 |
同包 | 支持 | 支持 | 支持 | |
子类 | 支持 | 支持 | ||
通用 | 支持 |
23.springAOP的术语
Aspect:切面,由一系列切点、增强和引入组成的模块对象,可定义优先级,从而影响增强和引入的执行顺序。事务管理(Transaction management)在java企业应用中就是一个很好的切面样例。所以他不是一个被代理的对象。
Join point:接入点,程序执行期的一个点,例如方法执行、类初始化、异常处理。 在Spring AOP中,接入点始终表示方法执行。
Advice:增强,切面在特定接入点的执行动作,包括 “around,” “before” and "after"等多种类型。包含Spring在内的许多AOP框架,通常会使用拦截器来实现增强,围绕着接入点维护着一个拦截器链。
Pointcut:切点,用来匹配特定接入点的谓词(表达式),增强将会与切点表达式产生关联,并运行在任何切点匹配到的接入点上。通过切点表达式匹配接入点是AOP的核心,Spring默认使用AspectJ的切点表达式。
Introduction:引入,为某个type声明额外的方法和字段。Spring AOP允许你引入任何接口以及它的默认实现到被增强对象上。
Target object:目标对象,被一个或多个切面增强的对象。也叫作被增强对象。既然Spring AOP使用运行时代理(runtime proxies),那么目标对象就总是代理对象。
AOP proxy:AOP代理,为了实现切面功能一个对象会被AOP框架创建出来。在Spring框架中AOP代理的默认方式是:有接口,就使用基于接口的JDK动态代理,否则使用基于类的CGLIB动态代理。但是我们可以通过设置proxy-target-class="true",完全使用CGLIB动态代理。
Weaving:织入,将一个或多个切面与类或对象链接在一起创建一个被增强对象。织入能发生在编译时 (compile time )(使用AspectJ编译器),加载时(load time),或运行时(runtime) 。Spring AOP默认就是运行时织入,可以通过枚举AdviceMode来设置。
24.BeanFactory和FactoryBean
1.BeanFactory是所有spring bean的容器根接口,给ioc容器提供了完整规范
2.FactoryBean是一种创建bean的方式,是对bean的以一种扩展
25.i++和++i
int i = 0;
i = i++;
i = i++;
System.out.println(i);//输出0
i = ++i;
System.out.println(i);//输出1
----------------------------------------
int a = 10;
System.out.println(a++ + a--);
// 就等于
int a = 10;
b = a++;(b=10,a=11)
c = a--;(c=11,a=10)
b+c=21
// 结果是21,先赋值再运算
int a = 10;
int b = 10;
int c = 10;
int d = 10;
System.out.println(a++ + a++);
System.out.println(b++ + ++b);
System.out.println(++c + c++);
System.out.println(++d + ++d);
// 21 22 22 23
27.==和equals、!=
1.基本类型比较
==:对于基本类型,比较的是两个变量的值是否相等
equals:不能用于比较基本类型,只能比较引用类型
2.引用类型比较
==:对于引用类型,比较的是两个引用是否指向同一个对象,即他们的内存地址是否相同
equals:默认情况下,equals比较的也是引用是否相同,但是很多类重写了equals方法用来比较基本内容,比如String。
3.方法本质
==:是运算符,可以直接使用
equals:是Object类的方法,需要通过对象调用,可以被重写。
4.性能
==通常比equals快一些,因为==只是简单的比较内存地址
1.==
用于基本数据类型比较,比较二者的值是否相等
用于引用数据类型比较,比较二者地址是否相等
不能用于基本数据类型和引用类型比较
2.queals
不能用于基本数据类型比较,因为equals是方法,继承自Objcec
用于进行对象的比较,比较二者的引用地址
Integer t1 = new Integer(12);
Integer t2 = new Integer(12);
Long u=new Long(12);
System.out.println(t1 == t2);// false
System.out.println(t1.equals(t2));// true
System.out.println(t1 != t2);// true
System.out.println(t1.equals(u));//false,源码里判断u如果不是Integer类型,直接返回false
Integer t3 = new Integer(129);
Integer t4 = new Integer(129);
System.out.println(t3.equals(t4));// true
Integer t5 = 12;
Integer t6 = 12;
System.out.println(t5 == t6);// true
Integer t7 = 129;
Integer t8 = 129;
System.out.println(t7 == t8);// false
-----------------------------------------------------------------------------------------
本题是一个自动拆装箱的考题(自动拆装箱JDK需在1.5上),下面的讨论都不针对新开辟对象的情况:
1、基本型和基本型封装型进行“==”运算符的比较,基本型封装型将会【自动拆箱】变为基本型后再进行比较,因此Integer(0)会自动拆箱为int类型再进行比较,显然返回true;
2、两个Integer类型进行“==”比较,如果其值在-128至127,那么返回true,否则返回false, 这跟Integer.valueOf()的缓冲对象有关,这里不进行赘述。
3、两个基本型的封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true
4、基本型封装类型调用equals(),但是参数是基本类型,这时候,先会进行【自动装箱】,基本型转换为其封装类型,再进行3中的比较。
int a=257;
Integer b=257;
Integer c=257;
Integer b2=57;
Integer c2=57;
System.out.println(a==b);
//System.out.println(a.equals(b)); 编译出错,基本型不能调用equals()
System.out.println(b.equals(257.0));
System.out.println(b==c);
System.out.println(b2==c2);
因此上面的代码的结果因此为 true, false, false, true
28.封装、继承、多态
封装主要是隐藏内部代码
继承主要是复用现有代码
多态主要是改写对象行为
29.&运算符、^运算符、~运算符
&运算符(且)
表示与,两个数都转为二进制,两个都为1,结果为1,否则结果为0。
13:01101
17:10001
结果:00001,即1
^运算符(或)
表示异或,相同是0,不同是1
14:1110
3:0011
14^3:1101,既13
~运算符(非)
表示按位取反
对每一位取反,1变为0,0变为1
30.抽象类和接口
抽象类
特点:
1.抽象类中可以有构造方法
2.抽象类中可以存在普通属性,方法,静态属性和方法。
3.抽象类中可以存在抽象方法。 抽象方法不能有方法体
4.如果一个类中有一个抽象方法,那么当前类一定是抽象类;抽象类中不一定有抽象方法。
5.抽象类中的抽象方法,需要有子类实现,如果子类不实现,则子类也需要定义为抽象的。
6.抽象类不能被实例化,抽象类和抽象方法必须被abstract修饰
7.抽象类方法中默认的访问权限jdk1.8之前是protected之后是default
8.抽象类中可以有main方法
9.抽象类中可以有static方法,但是不能有default方法
关键字使用注意:
1.抽象类中的抽象方法(其前有abstract修饰)不能用private、default、static、synchronized、native访问修饰符修饰。 (public和protected可以)
2.外部类的修饰符只能是不写,接口的修饰符只能是不写或者public
3.接口种的变量默认是public static final的,所以接口的成员变量必须赋值。方法默认是public abstract的。
4.抽象类中的非抽象方法可以被重写
5.抽象类可以有构造方法,只是不能实例化
6.抽象类不能多继承
接口
1.在接口中只有方法的声明,没有方法体。
2.在接口中只有【常量】,因为定义的变量,在编译的时候都会默认加上public static final
3.在接口中的方法,永远都被public来修饰。
4.接口中没有构造方法,也不能实例化接口的对象。(所以接口不能继承类)
5.接口可以实现多继承
6.接口中定义的方法都需要有实现类来实现,如果实现类不能实现接口中的所有方法则实现类定义为抽象类。
7.接口可以继承接口,用extends
8.接口中方法访问修饰符默认是public abstract的,但是JDK1.8之后接口中可以有static方法或者default方法,但是这两种方法必须有方法体。
9.接口中的方法用static修饰之后,就不能用abstract修饰了
10.接口中可以有main方法
接口方法默认是public abstract的,且实现该接口的类中对应的方法的可见性不能小于接口方法的可见性
------------------------------------------------------------------------------------------------------------
在JDK1.8之前的版本(不包括JDK1.8),接口中不能有静态方法,抽象类中因为有普通方法,故也可以有静态方法。
在JDK1.8后(包括JDK1.8),在抽象类中依旧可以有静态方法,同时在接口中也可以定义静态方法了。
------------------------------------------------------------------------------------------------------------
接口可以继承接口,而且可以继承多个接口,但是不能实现接口,因为接口中的方法全部是抽象的,无法实现;
如果是Java 7以及以前的版本,那么接口中可以包含的内容有:1. 常量;2. 抽象方法
如果是Java 8,还可以额外包含有:3. 默认方法;4. 静态方法
如果是Java 9,还可以额外包含有:5. 私有方法
抽象类可以实现接口,可以继承具体类,可以继承抽象类,也可以继承有构造器的实体类。
抽象类中可以有静态main方法;抽象类里可以没有抽象方法,没有抽象方法的抽象类就是不想让别人实例化它;
另外,抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。在继承了抽象类的子类中通过super(参数列表)调用抽象类中的构造方法,可以用于实例化抽象类的字段。
当抽象类只有有参构造时,子类(包括抽象类和非抽象类)必须定义有参构造,调用super(参数)
------------------------------------------------------------------------------------------------------------
下面总结常见的抽象类与接口的区别:
1.抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象;
2.接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现(java8中 接口可以有实现方法 使用default或static修饰);
3.接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量;
4.抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个类实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类;
5.抽象方法要被实现,所以不能是静态static的,也不能是私有private的,也不能被final修饰(试想一下,静态方法可以被类名直接调用,而类名直接调用一个没有实现的抽象方法没有意义)。
31.final关键字(最终)
1.final修饰变量,则等同于常量
2.final修饰方法中的参数,称为最终参数。
3.final修饰类,则类不能被继承
4.final修饰方法,则方法不能被重写。
5.final不能修饰抽象类(因为抽象类就是要被继承的,否则没有意义)
6.final修饰的方法可以被重载 但不能被重写
7.final修饰引用类型,是引用不能改变,而引用指向的内容是可以改变的
32.>> (算术右移)和 >>>(逻辑右移)
>>代表带符号右移,如果该数为正,则高位补0,若为负数,则高位补1;
>>>代表无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。
左移n位:相当于乘以2的n次方
右移n位:相当于除以2的n次方
正数情况下,>>和>>>的计算结果是一样的
而负数情况下,计算结果差距会非常大
在计算机中,负数通常使用补码表示。一个数的补码是其二进制表示取反后加1得到的
33.String类型创建对象
1.String对象的两种创建方式:
第一种方式: String str1 = "aaa"; 是在常量池中获取对象("aaa" 属于字符串字面量,因此编译时期会在常量池中创建一个字符串对象),
第二种方式: String str2 = new String("aaa") ; 一共会创建两个字符串对象一个在堆中,一个在常量池中(前提是常量池中还没有 "aaa" 字符串对象)。
System.out.println(str1==str2);//false
2.String类型的常量池比较特殊。它的主要使用方法有两种:
a.直接使用双引号声明出来的String对象会直接存储在常量池中。
b.如果不是用双引号声明的String对象,可以使用 String 提供的 intern 方法。 String.intern() 是一个 Native 方法,它的作用是: 如果运行时常量池中已经包含一个等于此 String 对象内容的字符串,则返回常量池中该字符串的引用; 如果没有,则在常量池中创建与此 String 内容相同的字符串,并返回常量池中创建的字符串的引用。
String s1 = new String("AAA");//指向的堆中的对象
String s2 = s1.intern();//指向常量池中对象
String s3 = "AAA";//指向常量池中对象
System.out.println(s2);//AAA
System.out.println(s1 == s2);//false,因为一个是堆内存中的String对象一个是常量池中的String对象,
System.out.println(s2 == s3);//true, s2,s3指向常量池中的”AAA“
35.基础数据类型
byte 字节数1,位数8
short 字节数2,位数16
char 字节数2,位数16
int 字节数4,位数32
long 字节数8,位数64
float 字节数4,位数32
double 字节数8,位数64
boolean 1bit
1字节(Byte)=8比特(bit)
默认的浮点数据类型是double,如果需要指定用float,需要在值后面加f
低 ---------------------------------------------> 高
byte -> short -> char-> int -> long -> float -> double
其中,bute,short转为char时,需要强转
由大到小需要强转,由小到大不需要
boolean类型与其他七种基本数据类型不能互相转换
各类型的表示方法:
byte:35B
int:35
short:35S
long:35L
double:2.12
float:2.13F
----------------------------------
Java中的四类八种基本数据类型
第一类:整数类型 byte short int long
第二类:浮点型 float double
第三类:逻辑型 boolean(它只有两个值可取true false)
第四类:字符型 char
基础数据类型
1.boolean
没有默认值
2.byte
占用一个字节,8位,赋值在-128到127之间
当把一个整数强转为byte时,会在-128到127之间循环
不存在常量后缀
3.short
占用两个字节,16位,取值在(-2^15~2^15-1)(-32768~32767),强转时,也是循环
不存在常量后缀
4.int
占用4个字节,32位,这个赋值过大时,会编译报错
不存在常量后缀
5.long
占用8个字节,64位
存在常量后缀
6.float
分配4个字节,34位
必须有常量后缀,不可省略
float变量在存储float型数据时默认保留8位有效数字,有效数字是从常量的第一数字开始算起;
如:float test3 = 1234.123456789f ; //则系统存储的是:1234.1234 ;
*当存在0开头的赋值时,则从与数字相邻的第一个0开始算起,一共取8位;
如:float test4 = 0.0123456789 ; //则系统存储0.01234567 ;float test4 = 0.00123456789 ; //则系统存储0.001234567 ;
7.double
8个字节,占64位
存在常量后缀,也可省略
8.char
2字节,16位,char是没有负数的
不存在常量后缀
赋值时,使用单引号扩起Unicode表中的任意一个字符
36.构造对象时,初始化顺序
父类静态变量、
父类静态代码块、
子类静态变量、
子类静态代码块、
父类非静态变量(父类实例成员变量)、
父类构造块
父类构造函数、
子类非静态变量(子类实例成员变量)、
子类构造块
子类构造函数。
------------------------------------------------------------------------------------------------------------
1、父类静态成员变量和静态代码块(顺序执行)
2、子类静态成员变量和静态代码块(顺序执行)
注意非静态方法,如果创建的是子类,则在执行父类的方法时,执行的是子类重写的方法
3、父类普通成员和代码块,再执行父类构造方法
4、子类普通成员和代码块,再执行父类构造方法
父类静态代码块->子类静态代码块->父类构造代码块->父类构造函数->子类构造代码块->子类构造函数
**非静态代码块初始化顺序在构造函数之前**
37.Map详解
1.HashMap
最常用的Map,使用键的HashCode值存储数据,访问速度快。遍历时,获取数据顺序随机。最多允许一条记录键为null,允许多条记录值为null。非线程安全,如需线程安全,可以使用Collections和SynchronizedMap方法,或者使用ConcurrentHashMap
2.HashTable
不允许记录的k,v值为null,线程安全,同一时刻只有一个线程能写入,所以写入较慢
3.LinkedHashMap
保存了数据插入的顺序,使用iterator遍历时,先得到的肯定是先插入的数据,遍历时毕HashMap慢。有一种情况例外,当HashMap容量很大,数据很小时,遍历素的可能不如LinkedHashMap,因为LinkedHashMap遍历只和数据有关,和容量无关,HashMap遍历时和容量有关
4.TreeMap
实现sortMap接口,能把保存的数据按照k值排序,默认按k值升序,也可指定比较器,遍历时,得到的记录时排过序的
38.值传递和引用传递
总的来说,值传递和引用传递的主要区别在于,值传递会创建副本且无法改变原始对象,而引用传递则不会创建副本且可以改变原始对象。
39.byte b = (byte)129;
输出b的值是-127
在计算机中,数值一律用补码来表示(存储)
正数:补码=反码=源码
负数:码除了符号位不变,其他位取反,补码=反码+1
40.Object中的基本方法
getClass(), hashCode(), equals(), clone(), toString(), notify(), notifyAll(), wait(), finalize()
41.super和this
super:
1:用来访问父类被隐藏的非私有成员变量
2:可以使用super访问父类被子类隐藏的变量或覆盖的方法。
3:每个子类构造方法的第一条语句,都是隐含地调用super()
4:用来调用父类中被重写的方法
super和this不能用在static修饰的方法中
42.线程启动方法
public static synchronized void main(String[] a){
Thread t=new Thread(){
public void run(){Sogou();}
};
t.run();
System.out.print("Hello");
}
static synchronized void Sogou(){
System.out.print("Sogou");
}
// 输出的是SogouHello,因为Thread.run()是调用方法,Thread.start()是启动线程
// 如果把t.run换成t.start则输出的是HelloSogou,因为此时的锁是该类的.class文件,当前是主线程占有锁,等主线程完成之后,新线程才能运行
43.父类和子类
当父类的方法是private时,对子类不可见,此时如果子类与有父类相同方法不算重写,
子类构造函数调用父类构造函数用super
子类重写父类方法后,若想调用父类中被重写的方法,用super
未被重写的方法可以直接调用
如果父类中只有有参构造函数,则子类构造函数必须调用
public class Xiaohua extends Person {
String name;
public Xiaohua(String name,int data) {
super(data);
name = name;
}
}
只要是被子类重写的方法,只要不是super调用,都是调用子类的方法
子类可以继承父类的所有成员,但是像private这样的,没有访问权限
44.字符ascii码值
一个简便的记忆法:0:48 A:65 a:97,数字连起来是486597 -> 486 597 -> 486 (486 + 111)
46.静态变量
public class Test {
static String str1;
public static void main(String[] args) {
String str2;
System.out.println(str1); //标记A
System.out.println(str2); //标记B 会在这行编译错误
}
}
1.静态变量的声明与初始化
声明:在Java中,静态变量(使用static关键字修饰)属于类而不是实例,它们在内存中只有一份拷贝。
初始化:静态变量可以在声明时直接初始化,也可以在静态代码块中进行初始化。如果在静态代码块中初始化,则必须在使用该变量之前完成赋值。
2.静态方法中变量的使用
访问限制:静态方法不能直接访问非静态变量,因为非静态变量属于类的实例,而静态方法在类加载时就已经存在,此时可能还没有实例化任何对象。
作用域:静态方法中可以使用静态变量,因为这些变量在类级别上是可见的。但是,如果静态方法中使用了一个未初始化的静态变量,编译器会报错,因为它无法确定该变量的值。
3.编译错误的原因
非法的前向引用:如果在静态方法中使用了一个尚未声明或赋值的变量,编译器会报“非法的前向引用”错误。这是因为编译器在编译时需要知道所有变量的值,以便生成正确的字节码。
未初始化的变量:即使变量已经在类的其他地方声明,如果在静态方法中使用它之前没有进行初始化,编译器也会报错。这是为了确保程序的健壮性和可预测性。
4.解决方案
显式初始化:在使用静态变量之前,确保已经在静态代码块或声明时对其进行了初始化。
检查变量的作用域:确保在静态方法中使用的变量是静态变量,而不是实例变量。
缓存问题
缓存穿透:高并发下查询一个不存在的数据
解决方案:空结果进行缓存,并加入短暂过期时间
缓存雪崩:所有缓存的生效时间都一样,导致某一时间缓存集体失效
解决方案:加入随机生效时间,防止集体失效
缓存击穿:对于一些热点数据,在失效之前突然有大并发访问同一个key,会导致所有的请求都到数据库
解决方案:加锁,大并发只让一个人去查,查到之后放入缓存,其他请求再查询缓存
在分布式情况下,查完数据库后,要先放入缓存再释放锁,不然就可能会查多次数据库(锁时序问题)
@Autowired和@Resource的区别
(1)提供方:@Autowired是由org.springframework.beans.factory.annotation.Autowired提供,换句话说就是由Spring提供;@Resource是由javax.annotation.Resource提供,即J2EE提供,需要JDK1.6及以上。
(2)注入方式:@Autowired只按照byType注入;@Resource默认按byName自动注入,也提供按照byType注入;
(3)属性:@Autowired按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。@Resource有两个中重要的属性:name和type。name属性指定byName,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。需要注意的是,@Resource如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。
浅拷贝和深拷贝
浅拷贝只复制所考虑的对象,而不复制它所引用的对象。现象就是原对象改了对象成员变量的值,克隆对象里的也会变
深拷贝需要层层重写clone方法,会新创建对象空间,开销比较大
java里深克隆一个对象,可以先实现序列化接口,然后把对象写在一个流里,再从流里读出来,就是重建了一个对象
47.queue
1.LinkedBlockQueue是一个基于节点链接的可选是否有界的阻塞队列,不允许null值。线程安全,先进先出
2.PriorityQueue是一个无界队列,不允许null值,入队和出队的时间复杂度是O(log(n)),不是先进先出,每次取出的是优先级最高的元素,线程不安全
3.ConcurrentLinkedQueue是一个基于链接节点的无界队列,线程安全,先进先出,不允许null值
48.初始化静态成员变量,对象会先被赋值为null,后面进行实例化
public class Test {
static Test test1 =new Test();
static Test test2 =new Test();
{
System.out.println("构造块");
}
static{
System.out.println("静态块");
}
public static void main(String[] args) {
Test test = new Test();
}
}
/**
打印的是
构造块
构造块
静态块
构造块
jvm加载class时,先初始化静态成员变量,test1、test2先被赋值为null,后面他俩需要进行实例化,先调用构造块,再调用默认构造方法,所以打印了两个”构造块“,然后到了main方法里的创建Test对象,先调用静态代码块,然后调用构造块,再调用构造方法
*/
发生死锁的四个必要条件:
资源互斥:当资源被一个线程占用时,其他线程不能使用。
请求和保持:当一个线程因为请求资源而阻塞时,对已持有资源保持不放
不可剥夺:资源请求者不能强制从资源占有者手中抢夺资源,资源只能由占有者主动释放。
环路等待:存在一个线程链,链中的每一个线程都占有下一个线程所需的资源。
13.找出一个整数数组中第二大的数
public class SecondLargestNumber {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
System.out.println("第二大的数是: " + findSecondLargest(arr));
}
public static int findSecondLargest(int[] arr) {
int max = Integer.MIN_VALUE;
int secondMax = Integer.MIN_VALUE;
for (int num : arr) {
if (num > max) {
secondMax = max;
max = num;
} else if (num > secondMax && num < max) {
secondMax = num;
}
}
return secondMax;
}
}
5.公鸡每只5文钱,母鸡每只3文钱,3只小鸡1文钱,用100文钱买了100只鸡,其中公鸡、母鸡、小鸡各多少只?用java代码实现
public class Main {
public static void main(String[] args) {
for (int x = 0; x <= 20; x++) {
for (int y = 0; y <= 33; y++) {
int z = 100 - x - y;
if (5 * x + 3 * y + z / 3 == 100 && z % 3 == 0) {
System.out.println("公鸡:" + x + "只,母鸡:" + y + "只,小鸡:" + z + "只");
}
}
}
}
}
16.打印杨辉三角
public class YangHuiTriangle {
public static void main(String[] args) {
int numRows = 10; // 可以修改为需要打印的行数
printYangHuiTriangle(numRows);
}
public static void printYangHuiTriangle(int numRows) {
int[][] triangle = new int[numRows][];
// 构造
for (int i = 0; i < numRows; i++) {
triangle[i] = new int[i + 1];
triangle[i][0] = 1;
triangle[i][i] = 1;
for (int j = 1; j < i; j++) {
triangle[i][j] = triangle[i - 1][j - 1] + triangle[i - 1][j];
}
}
// 打印
for (int i = 0; i < numRows; i++) {
for (int j = 0; j <= i; j++) {
System.out.print(triangle[i][j] + " ");
}
System.out.println();
}
}
}
18.给定如下数组String[] str={"A","C","H","R"}; String[] str2={"R",H","A"}; 要求参照str2的顺序给str排序,没有在str2中的字母放在最后,不用排序
26.假设a是由线程1和线程2共享的初始值为0的全局变量,则线程1、2同时执行下面代码,最终a的结果有哪几种
boolean isOdd = false;
for (int i = 1; i <= 2; ++i) {
if (i % 2 == 1) {
isOdd = true;
} else {
isOdd = false;
}
a += i * (isOdd ? 1 : -1);
}
这个逻辑就是先+1再-2
1.线程1执行完再线程2执行,1-2+1-2=-2
2.线程1和2同时+1,再-2不同时,1-2-2=-3
3.线程1和2不同时+1,同时-2,1+1-2=0
4.线程1和2既同时+1又同时-2,1-2=-1
34.StringBuffer
public static void main(String[] args) {
StringBuffer a = new StringBuffer("A");
StringBuffer b = new StringBuffer("B");
test(a,b);
System.out.println(a);
System.out.println(b);
}
public static void test(StringBuffer x, StringBuffer y) {
x = x.append(y);
y = x;
}
// 输出AB B