-
线程的6种状态:
NEW 新建状态
RUNNABLE 可运行状态
BLOCKED 锁阻塞状态
WAITING 无限期等待状态
TIMED_WAITING 有限期等待状态
TERMINATED 死亡状态 -
元注解是什么?举例。
元注解是对注解进行基本信息设置的注解。
@Target用于描述注解的使用范围,比如这个注解是用在类上面还是方法上面;
@Retention用于描述注解的保存策略,是保留到源代码中、Class文件中、还是加载到内存中;
@Documented用于描述该注解将会被javadoc生产到API文档中;
@Inherited用于表示某个被标注的类型是被继承的,如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。 -
举例说明,如果使用Class类型分别表示基本类型、数组类型、引用类型,Class c1 = …;
基本数据类型:
Class c1=int.Class;
Class c2=int[].Class;
Class c3=String.Class。 -
第1,2个数是1,从第三个数开始,当前的数是前面两个数的和,要求用数组完成方法体。
for循环,通过数组下标确定第3个元素开始的值。
package com.chouhan.test1;
/*
4.有一组数据:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 .....
特点:从第三个数开始,当前的数是前面俩个数相加之和
要求1:写出一方法,给方法传一个参数,可以返回一个这样序列的数组,这个参数表示这个序列的长度:
例如:test(1) 返回数组{1}
test(2)返回数组{1,1}
test(3)返回数组{1,1,2}
test(4)返回数组{1,1,2,3}
依次类推:
要求2:方法内部的代码也要使用数组实现
要求3:方法的声明如下所示
public int[] test(int num){
int[] a = null;
//实现代码
return a;
}
*/
public class Test1 {
public static int[] test(int num) {
//定义一个数组,数组的长度就是序列的长度
int[] a=new int[num];
//前两个数是固定的
if(num==1) {
a[0]=1;
}else if(num==2) {
a[0]=1;
a[1]=1;
//从第三个数开始,每个数是前两个数相加之和
}else {
a[0]=1;
a[1]=1;
//从数组的第三个元素,也就是下标为2开始,循环给数组元素赋值
for (int i = 2; i < a.length; i++) {
//当前这个数的前两个数的和
a[i]=a[i-1]+a[i-2];
}
}
return a;
}
public static void main(String[] args) {
//测试输出满足规律的数组,数组的长度为5
int[] test=test(5);
//迭代器的方式输出数组
for (int i : test) {
System.out.println(i);
}
}
}
-
int a=256;先用toByteArray()方法把a转换成字节数组,然后用Arrays.toString()的方式输出a,代码的运行结果?
[0,1,0,0]
toByteArray()方法是把字符串转换为新的字符数组。
java.util.Arrays类:该类包含用于操作数组的各种方法(如排序和搜索)。
toString()方法是指返回对象的字符串表示形式。 -
几种进制下的16如何声明?
int a1=0b10000;
//(0000 0000 0000 0000 0000 0000 0001 0000)2进制,加0b或者补齐0一直到32位;
int a2=020;
//8进制,把2进制转换成8进制,再以0开头;
int a3=16;
//10进制
int a4=0x10;
//16进制,把2进制转换成16进制,再以0x开头。
-
Class.forName(“com.briup.User”);代码的作用是什么?返回值是什么?
作用是将User类加载到内存中,返回的是User的Class对象。
forName()方法:返回与给定字符串名称的类或接口相关联的类对象。 -
分析代码的运行结果?为什么?
public void test(int... arr,String str){
System.out.println(arr.length + str.length());
}
public static void main(String[] args){
int[] arr = {1,2,3};
String str = "hello";
t.test(arr,str);
}
编译报错。
因为可变参数必须要放在参数列表的最后一个位置。用到可变参数可以存放0~n个值。
如果参数列表正确,arr.length和str.length()的返回值一致,所以+号不是拼接,而是3+5=8。、
- 代码的运行结果?为什么?
String str1 ="hello";
String str2 = new String("hello").intern();
System.out.println(str1.equals(str2));
System.out.println(str1 == str2);
true
true
因为String类的intern()方法可以在JVM运行期间,强行使用字符串常量池。
intern():返回字符串对象的规范表示。
当调用intern方法时,如果池已经包含与equals(Object)方法确定的相当于此String对象的字符串,则返回来自池的字符串。 否则,此String对象将添加到池中,并返回对此String对象的引用。
由此可见,对于任何两个字符串s和t , s.intern() == t.intern()是true当且仅当s.equals(t)是true 。
- 请在Action接⼝中定义⼀个泛型⽅法test,要求传⼊⼀个任意引⽤类型的参数,可以返回这个类型的对象。
例如,传⼊String类型,则返回String类型对象
例如,传⼊Student类型,则返回Student类型对象
普通方法:修饰符 返回类型 方法名(参数列表)
泛型方法:修饰符 返回类型 方法名(T t)
接口里只能写抽象方法:(默认是public abstract)
public Interface Action{
<T> T test(Class<T> c);
}
-
Integer i1=127;Integer i2=127;syso(i1==i2);返回什么,为什么?
因为Integer类中会对byte范围的数字进⾏缓存。
Integer源码:IntegerCache类,缓存了-128~127,不超出范围就不会创建新的Integer对象。 -
基本数据类型和引用数据类型的本质区别?(一句话)
是否可以指向对象。 -
代码补全:
package com.chouhan.test1;
import java.util.ArrayList;
import java.util.List;
/*
* 补全代码:要求把if条件中的代码补全,最后把list集合中的四个值依次输出,
* 同时如果当前的值是tom,则需要把该值从list中删除掉。
*/
public class Test5 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("tom");
list.add("briup");
//计算集合的有效元素个数:size()
for (int i = 0; i < list.size(); i++) {
//获取集合指定下标的元素get()
System.out.println(list.get(i));
//把字符串放前面,是为了避免list的某个元素可能为空,会抛出空指针异常
if ("tom".equals(list.get(i))) {
// 代码补全
if ("tom".equals(list.get(i))) {
//remove():删除指定集合指定下标的元素
list.remove(i); // list.remove("tom");也可以
i--;
}
}
}
}
}
- 递归就是方法里面再调用方法。
package com.chouhan.test1;
/*
* 递归:java中的方法调用有⼀种情况称为递归,就是⼀个方法内部再调用自己,同时提供⼀个退出方法条件。
* 要求:
* 1.在go⽅法内部完成代码
* 2.实现从1累加到100的和
* 3.go⽅法内部的所写的代码不能超过俩句,注意⼀个分号就是⼀句代码。
*/
public class Test3 {
public static void main(String[] args) {
Test3 t = new Test3();
int sum = t.go(100);
System.out.println(sum);
}
public int go(int i) {//递归
if(i==1) {
return 1;
}else {
return i+go(--i);//go(i-1)也可以
}
}
}
- InputStream类中有如下俩个⽅法:
public int read();
public int read(byte b[]);
分别介绍每个⽅法的参数和返回值的含义。
参考答案:
int read() 没有参数,返回值是读到的流中的下⼀个字节值
int read(byte b[]) 参数是⼀个字节数组,⽤来存放从流中读到的字节值,直到该字节数组存满,或者读到了流的末
尾,则⽅法结束。返回值是本次读到的字节的个数。
//InputStream的3个read方法如何理解?
int read();//没有参数,返回的值是从输入流读取的下一个字节。
int read(byte[] b);//从输入流读取一些字节数,并将它们存储到缓冲区字节数组b中。
int read(byte[] b,int off,int length);//从输入流读取最多len个字节的数据到一个字节数组。
- 假设在线程的等待池中,现在有很多线程都阻塞在这⾥,notifyAll⽅法可以叫醒等待池中的线程。
问题:调⽤哪个对象的notifyAll⽅法?叫醒等待池中的哪些线程?
调⽤锁对象的notifyAll⽅法,叫醒等待池中所有等待这把锁的线程,等待另外锁的线程,则不叫醒。
notifyAll()唤醒的是谁?谁调用这个方法?
查看API:notifyAll()唤醒正在等待对象监视器的所有线程。该对象的监视器的所有者的线程。
wait():导致当前线程等待,直到另一个该对象的监视器的所有者的线程调用此对象的notify()方法或notifyAll()方法,或指定的时间已过。
notify():唤醒正在等待对象监视器的单个线程。 如果任何线程正在等待这个对象,其中一个被选择被唤醒。 选择是任意的,并且由实施的判断发生。 线程通过调用wait方法之一等待对象的监视器。 唤醒的线程将无法继续,直到当前线程放弃此对象上的锁定为止。 唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正在积极地竞争在该对象上进行同步; 例如,唤醒的线程在下一个锁定该对象的线程中没有可靠的权限或缺点。
wait(),notify(),notifyAll()方法只能由作为该对象的监视器的所有者的线程调用。 线程以三种方式之一成为对象监视器的所有者:
- 通过执行该对象的同步实例方法。
- 通过执行在对象上synchronized synchronized语句的正文。
- 对于类型为Class的对象,通过执行该类的同步静态方法。
总结:Object类中有三个方法: wait()、notify()、notifyAll(),当一个对象在线程同步的代码中,充当锁对象时,在synchronized同步的代码块中,就可以调用这个锁对象的这三个方法。即:任何对象一定有这三个对象,因为是Object类中继承的方法;只有对象作为锁对象的时候才能调用;只有在同步的代码块中,才可以调用。
- 分析代码的运行结果,为什么?
package com.chouhan.test1;
public class Test9 {
public void test()throws Exception{
//getClass:返回此 Object的运行时类。
//所以这里锁的this是指当前类对象Test9,而返回的是Test9.class对象
synchronized (this.getClass()) {
for(int i=0;i<100;i++){
if(i==10){
//wait是只有持有锁对象的进程才能调用的方法
//但因为每个类都继承了Object类的三个方法wait(),notify(),notifyAll(),
//所以Test9也有wait方法,编译时不会报错,这里wait的this虽然也是指Test9,
//但锁对象本身不能wait调用方法,要让调用test方法的线程调用wait,所以运行会报错。
this.wait();
}
}
}
}
}
编译不报错,运⾏报错,只有锁对象才能调⽤wait⽅法,这⾥的锁对象是Class对象⽽不是this。
- 解释代码1的含义:
public class Hello {
public static void main(String[] args)throws Exception {
Thread t = new Thread(){
public void run() {
//很耗时的操作
}
};
t.start();
t.sleep(6000);//代码1
}
}
sleep是Thread类中的静态⽅法,所以代码1可以写出Thread.sleep(6000),意思是让当前线程睡眠6秒钟,⽽这⾥的当前线程指的是main线程,所以最终是main线程睡眠6秒钟。
main线程进入了sleep,而不是t进入了sleep。sleep是一个本地的静态方法。
-
enum枚举是不是类?为什么?
枚举是⼀种特殊的java类。枚举的class⽂件,使⽤javap命令进行反编译之后,可以看到,它是⼀个final修饰的类,并且指定了继承了java.lang.Enum⽗类。 -
有以下代码
ArrayList list = new ArrayList();
代码编译运行会不会报错?为什么?
参考答案
编译报错
ArrayList<Object>
和ArrayList<String>
//是俩个不同的类型,并且没有任何关系。
ArrayList<?>
//这才是所有ArrayList加了泛型类型的父类型 -
解释代码1的含义:
public interface Test{
<T> T t(T t);//代码1
}
这是一个泛型接口,方法名字为t,方法的参数类型T,由将来用户实际传的值的类型所决定,并且方法的返回类型T和参数类型T保持一致,形参名为t。
-
Set和List可以使用迭代器遍历,Map集合为什么不能迭代,不能使用iterator?
因为Set和List集合都继承了Collection接口,Collection接口继承了Iterator接口,Iterator接口中有用于遍历的iterator方法,而Map集合没有继承Iterator接口。 -
匿名内部类有没有构造器?
有构造器,只是我们不能编写和调用(因为没名字),它会有一个默认的构造器的。把编译生产的class文件,使用javap命名进行反编译就可以看到这个默认的构造器。 -
接口可以继承接口吗?举例。
Map接口中有一个Entry<K,V>接口(Entry不是类)。Stream接口中有一个Builder接口。 -
抽象类不能使用new创建对象,那么它的构造器的作用是是什么?
用于让子类调用。 -
编译的运行结果?为什么?
public class Test{
//不能在构造器赋值
public static final String s;
public Test(){
s = "hello";
}
//可以在静态代码块赋值
private final static String str;
static {
str="123";
}
public static void main(String[] args){
System.out.println(s);
}
}
static final修饰的属性,只能在声明的时候或者在static代码块中赋值,而且只能赋一次值。
package com.chouhan.test1;
public class Test4 {
//可以在静态代码块赋值
private final static String str;
static {
str="123";
}
//不能在构造器赋值
private final static String str=null;
public Test4() {
str="123";
}
}
- 父类引用不能调用子类新定义的方法。
package com.chouhan.test1;
/*
* 编译运行后的结果是什么?为什么?
*/
public class A{
public void test1() {
System.out.println("A test1");
}
}
class B extends A {
public void test1() {
System.out.println("B test1");
}
public void test2() {
System.out.println("B test2");
}
public static void main(String[] args) {
A a = new B();
a.test1();
// a.test2();
}
}
//编译报错,变量a是A类型的,无法调用到test2方法,因为test2方法是子类B中独有的方法
- 父类的构造器和子类重写的构造器?
public class A{
public void sayHello(){
System.out.println("hello A");
}
public A(){
this.sayHello();
}
}
class B extends A{
public void sayHello(){
System.out.println("hello B");
}
public static void main(String[] args){
new B();
}
}
输出:hello B
子类继承父类,在调用方法的时候,如果子类中没用重写,那么调用的是从父类继承的方法,如果子类重写了这个方法,那么将会调用到子类中重写后的方法。
-
重写。
方法名必须相同
参数列表必须相同
返回类型可以相同,也可以不同:
(1)如果父类的返回类型是引用类型,子类重写后的方法返回类型可以和父类方法的返回类型保持一致,也可以是父类方法返回类型的子类型。
(2)如果父类的返回类型是基本类型,那么子类重写后的返回类型必须和父类的保持一致。
访问权限修饰符范围可以扩大但是不能缩小
抛出异常类型可以缩小但是不能扩大 -
重载。
方法名相同;
参数列表不同:参数的类型不同;参数的个数不同;参数的顺序不同。
方法的修饰符、返回类型、抛出异常这些地方没有限制。 -
子类没有指定去调用有参构造器,所以默认就会去调用无参构造器,无参构造器被有参构造器覆盖,所以编译时就会报错。
package com.chouhan.test1;
/*
* 编译运行后的结果是什么?为什么?
*/
public class SubA extends Base{
public SubA(String s){
System.out.println("SubA: "+s);
}
public static void main(String[] args){
new SubA("hello");
}
}
class Base{
public Base(String s){
System.out.println("Base: "+s);
}
//显式的定义出父类的无参构造器就可以了
public Base() {}
}
/*
* 编译报错
* 因为父类中没有无参构造器,而子类构造器中隐式调用了父类的无参构造器
*/
32.main方法在执行过程的中,代码1中的this代表的谁?谁调用这个方法,谁就是this。
package com.chouhan.test1;
public class Test7 {
public void sayHello(){
System.out.println(this);//代码1
}
//public static void main(){
public static void main(String[] args){
Test7 t1 = new Test7();
Test7 t2 = new Test7();
t1.sayHello();
t2.sayHello();
}
}
/**
* 输出的是对象t1和t2的地址值。
* 当代码执行t1.sayHello()的时候,代码1中的this代表的是t1,
* 当前代码执行t2.sayHello()的时候,代码1中的this代表的是t2。
*/
/* 如果main()里面不写String[] args,就无法编译,控制台加载这个类,就会打印错误:
* 错误: 在类 com.chouhan.test1.Test7 中找不到 main 方法, 请将 main 方法定义为:
* public static void main(String[] args)
* 否则 JavaFX 应用程序类必须扩展javafx.application.Application
*/
- 分别列出代码1和代码2输出结果是什么?
1
tom
package com.chouhan.test1;
public class Test6 {
public static void a1(int a) {
a++;
}
public static void a2(Student s) {
s.setName("tom");
}
public static void main() {
int a = 1;
Test6.a1(a);
System.out.println(a);//1
Student s = new Student();
s.setName("zs");
Test6.a2(s);
System.out.println(s.getName());//tom
}
}
class Student{
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 列出对主函数声明有误的代码。
public static void main(String args[]) //代码1
static public void main(String[] args) //代码2
public void static main(String[] args) //代码3
static public void main(String... args) //代码4
public void main(String args[]) //代码5
public static void main(String... args) //代码6
public static void main(String[] test) //代码7
参考答案:
代码3和代码5
主函数的声明:
定义数组时,[]可以在前也可以在后;
修饰符public和static的顺序可以调换;
定义返回值void的位置只能放在方法名前面;
可变参数列表可以替代数组的表示;
static的作用是允许这个类中的其他方法调用这个static修饰的方法,可以不写;
方法名是可以自己定义的,不一定要是main。
-
数组对象如何获取长度?有哪些方法?
.length,直接获取属性;从Object类中继承的方法,toString()方法。 -
列出你认为编译会报错的代码
int[] a = new int[2]; //代码1
int[] b = new int[2]{100,101}; //代码2
int[] c = {100,101}; //代码3
int[] d; //代码4
d = {100,101}; //代码5
int[] e; //代码6
e = new int[]{100,101}; //代码7
代码2和代码5这俩处会编译报错
创建数组对象时:
可以只定义长度,先不给其赋值;
创建数组对象的同时赋值,就不能同时再指定长度;
简便方式创建数组时,不能分开声明和赋值;
显式声明创建数组类型变量,然后再创建对象并赋值也是可以的。
只有简便方式不能分开写,其他方式定义数组都可以把声明和赋值分开。
Java中的静态初始化和动态初始化,静态初始化是声明的时候就初始化,动态初始化是先声明,再动态初始化。
- Java数组对象和java.util.Arrays类是什么关系?
java.util.Arrays类是数组的工具类,该类中有很多静态方法可以用来操作数组对象,例如给数组元素排序、查找数组中某个元素的下标等等。
38.有以下代码:
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
if(j == 1){
break;
}
}
}
如何让break语句可以跳出外层循环(变量i所在的循环)?用代码举例说明(代码不需写全,能明确表达出即可)
lableA:for(int i=0;i<10;i++){
lableB:for(int j=0;j<10;j++){
if(j == 1){
break lableA;
}
}
}
给循环定义一个label标签,然后使用break跳出循环。
- 以下代码输出结果是多少?
System.out.println(32336>>4);
//>>4的作用相当于除以2^4,所以的32336除以16,等于2021。
参考答案:
2021
- 有以下代码:
byte a = 1;//代码1
a+=1; //代码2
//a=a+1; //代码3
a=(byte) a+1;
System.out.println(a);//代码4
代码编译运行后的结果是什么?
参考答案:
编译报错,代码3编译不通过
代码2时,byte只是a的数值+1,a的类型依旧是byte类型,但代码3时的a和1相加,这个1默认是int类型,所以a+1计算完必须先转换回byte类型,才能赋值给byte类型的a。
- obj instanceof Student 请说明该代码的含义?注意引用和对象的描述
参考答案:
这句代码是指在运行时,引用obj所指向对象的实际类型,是不是Student类型或者Student的子类型,注意是obj所指向的对象类型,而不是obj的类型。
instanceof:判断当前对象所指向的类型是否正确。
- 有以下代码
int a = 15;
int b = 3;
把变量a和变量b的值进行交换,并且要求不能使用第三个变量。(至少写出俩种方案)
交换int两个变量的值:(1)+、-;(2)^:异或;(3)*、/。
//结合内存图理解!!!
a = a+b;//把a和b存放的两块空间加到一起给a,b没变
b = a-b;//把a-没变的b,就等于了之前的a,把这个之前的a赋值给b,但这时第1步的是总和的a还没变
a = a-b;//再把第1步得到的总和的a-已经变成最开始a大小的b,就=b了,把这个最开始的b给新的a。
--------
a = a^b;
b = a^b;
a = a^b;
--------
a = a*b;
b = a/b;
a = a/b;
- java中整型默认类型是int,浮点型默认类型是double,那么以下俩句代码会不会编译出错?为什么?
byte b = 1;
float f = 10.5;
参考答案:
编译会出错,因为10.5默认是double类型的,double类型是双精度的浮点数,float是单精度的浮点数,双精度的数字如果用单精度的变量接收有可能会丢失精度的。
int到byte隐式的强制转换,但是float和double在计算机底层的保存方式不同。
- 观察以下代码:
char c1 = '\u0000';
char c2 = 0;
char c3 = 00;
char c4 = ' ';//单引号中有一个空格
c1分别和c2、c3、c4比较是否相等(返回ture或false)?
参考答案:
c1==c2 为true相等
c1==c3 为true相等
c1==c4 为false不相等
char的默认值问题:char c4=" ";//c4不会等于char的默认值,因为空格会有自己的值。char c2和char c3等于0、00、000,都可以表示char的默认值。
-
int类型最大值最小值。
最小值是-2的31次方,最大值是2的31次方减1。
byte类型的最大值的127,最小值是-128;而int对应的包装类Integer中缓存了byte范围的-128~127,不是int类型的范围。 -
java中的三种注释分别是什么?把class文件反编译后是否可以获取代码中的注释?
单行注释 //注释
多行注释 /注释/
文档注释 /*注释/
不能。 -
假设现在我们登录unix服务器后所处的位置在/home/tom;/home/tom目录下有俩个子目录:/home/tom/src,/home/tom/bin我们在当前/home/tom下使用vi命令分别编写俩个java源文件:vi src/Student.java (com.briup包下),vi src/StudentTest.java (com.briup包下)。StudentTest.java中有主函数,其中调用到了Student类中的方法,编译这俩个类,并且运行StudentTest类。请写出编译运行的命令?
要求:这俩个类要一个一个编译,并且编译好的东西放到bin下面。执行所有命令的时候,我们所在的路径都是/home/tom
javac -d bin src/Student.java
javac -d bin -cp bin src/StudentTest.java
java -cp bin com.briup.StudentTest
Linux编译运行.java文件的命令。javac是编译,java是运行。
-
字节码验证验证的是什么?
字节码版本和JVM是否兼容,.class文件能不能用
代码不能破坏系统的完整性
运行时堆栈没有溢出
参数类型是否正确
类型转换是否正确
变量要在使用之前进行初始化
方法调用与对象引用类型间要匹配 -
执行一个普通java类(有主函数)时,一般会涉及到哪些类加载器?CLASSPATH和哪个加载器有关?什么关系?
参考答案:
启动类加载器
扩展类加载器
应用类加载器
CLASSPATH和应用类加载器有关,应用类加载器会通过CLASSPATH中配置的路径,来查找当前需要执行的java代码所存在的class文件。 -
配置jdk的环境变量,JAVA_HOME、CLASSPATH、Path的作用。
安装JDK后,需要配置的三个环境变量分别是什么?以及每个环境变量代表的含义是什么?
参考答案:
JAVA_HOME:JDK安装路径;
PATH:JDK中bin目录所在路径;
CLASSPATH:当前要执行的java类(class文件)所在路径。