java面试题[笔记](10道)

1—线程

1.1—runable创建线程

3.2 实现Runnable接口
自定义类实现Runnable,实现里面run()方法,创建Thread类,使用Runnable接口的实现对象作为参数传递给Thread对象,调用Strat方法。
优点:线程类可以实现多个几接口,可以再继承一个类
缺点:没返回值,不能直接启动,需要通过构造一个Thread实例传递进去启动

public class ThreadDemo2 implements Runnable {
    @Override
    public void run() {
        System.out.println("通过Runnable实现多线程,名称:"+Thread.currentThread().getName());
    }
}

public static void main(String[] args) {
        ThreadDemo2 threadDemo2 = new ThreadDemo2();
        Thread thread = new Thread(threadDemo2);
        thread.setName("demo2");
    	// start线程执行
        thread.start();
        System.out.println("主线程名称:"+Thread.currentThread().getName());
}

// JDK8之后采用lambda表达式
public static void main(String[] args) {
    Thread thread = new Thread(() -> {
        System.out.println("通过Runnable实现多线程,名称:"+Thread.currentThread().getName());
    });
    thread.setName("demo2");
    // start线程执行
    thread.start();
    System.out.println("主线程名称:"+Thread.currentThread().getName());
}

1.2—通过线程池创建线程

自定义Runnable接口,实现run方法,创建线程池,调用执行方法并传入对象
优点:安全高性能,复用线程
缺点: jdk5后才支持,需要结合Runnable进行使用

public class ThreadDemo4 implements Runnable {
    @Override
    public void run() {
        System.out.println("通过线程池+runnable实现多线程,名称:" +
                           Thread.currentThread().getName());
    }
}

public static void main(String[] args) {
    	// 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for(int i=0;i<10;i++){
            // 线程池执行线程任务
            executorService.execute(new ThreadDemo4());
        }
        System.out.println("主线程名称:"+Thread.currentThread().getName());
        // 关闭线程池
        executorService.shutdown();
}

一般常用的Runnable 和 第四种线程池+Runnable,简单方便扩展,和高性能 (池化的思想)

1.3.–继承Thread类

步骤:

1.定义一个类继承Thread类
2.重写run方法:里面写线程要运行的任务代码
3.创建Thread子类对象
4.调用start方法:开启线程并调用run方法

1.4.-实现Callable接口

步骤

1.创建Callable的实现类
2.重写call方法,将线程的任务代码封装到call方法中

—线程的几个状态

说说线程的生命周期和状态?

Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态(图源《Java 并发编程艺术》4.1.4 节)。

Java 线程的状态

2. Java中可以有哪些方法来保证线程安全?

加锁:比如synchronize/ReentrantLock

使用volatile声明变量,轻量级同步,不能保证原子性(需要解释)

使用线程安全类,例如原子类 AtomicXXX等

使用线程安全集合容器,例如:CopyOnWriteArrayList/ConcurrentHashMap等

ThreadLocal本地私有变量/信号量Semaphore等

3.–辗转相除求最大公因数(临时加的)

求2个数m,n(m>n)的最大公因数

//解题思路:
若m%n==0,则n是m和n的最大公因数。
若m%n==k,则递归执行n%k==k2,k%k2==k3 … 直到取余的结果为0,则被取余数kn就是 m和n的最大公因数!
答案如下:

public class Test13 {
	public static void main(String[] args) {
		System.out.println(f5(35, 12));
	}
/**
 * 求2个数的最大公因数
 * @param m
 * @param n
 * @return
 */
static int f5(int m, int n) {
	if (n == 0) {
		return m;
	}
	return f5(n, m % n);
}

4.–练习7:求最2个数的最小公倍数

求2个数m,n(m>n)的最小公倍数

解题思路:

最小公倍数,可以通过m和n的乘积除以二者的最大公约数,即可得到!
公式:最小公倍数 = m* n / 最大公约数

答案如下:

public class Test13 {
	public static void main(String[] args) {
		// 最大公约数
		System.out.println(f5(16, 12));
		// 最小公倍数
		System.out.println(16*12/f5(16, 12));
	}
/**
 * 求2个数的最大公因数
 * @param m
 * @param n
 * @return
 */
static int f5(int m, int n) {
	if (n == 0) {
		return m;
	}
	return f5(n, m % n);
}

5.–为什么说 Java 语言“编译与解释并存”?

这是因为 Java 语言既具有编译型语言的特征,也具有解释型语言的特征。因为 Java 程序要经过先编译,后解释两个步骤,

  • 由 Java 编写的程序需要先经过编译步骤,生成字节码(.class 文件),

  • 这种字节码必须由 Java 解释器来解释执行。

6.–基本类型和包装类型的区别?

  • 包装类型不赋值就是 null ,而基本类型有默认值且不是 null
  • 包装类型可用于泛型,而基本类型不可以。
  • 基本数据类型的局部变量存放在 Java 虚拟机栈中的局部变量表中,基本数据类型的成员变量(未被 static 修饰 )存放在 Java 虚拟机的堆中。包装类型属于对象类型,我们知道几乎所有对象实例都存在于堆中。
  • 相比于对象类型, 基本数据类型占用的空间非常小。

7.–包装类型的常量池技术?

  • Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,
  • Character 创建了数值在 [0,127] 范围的缓存数据,
  • Boolean 直接返回 True or False

8.–面向对象和面向过程的区别

两者的主要区别在于解决问题的方式不同:

  • 面向过程把解决问题的过程拆成一个个方法,通过一个个方法的执行解决问题。
  • 面向对象会先抽象出对象,然后用对象执行方法的方式解决问题。

9.–成员变量与局部变量的区别有哪些?

  • 语法形式 :从语法形式上看,成员变量是属于类的,而局部变量是在代码块或方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
  • 存储方式 :从变量在内存中的存储方式来看,如果成员变量是使用 static 修饰的,那么这个成员变量是属于类的,如果没有使用 static 修饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则存在于栈内存。
  • 生存时间 :从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动生成,随着方法的调用结束而消亡。
  • 默认值 :从变量是否有默认值来看,成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值(一种情况例外:被 final 修饰的成员变量也必须显式地赋值),而局部变量则不会自动赋值。

10.–创建一个对象用什么运算符?对象实体与对象引用有何不同?

  • new 运算符,new 创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。

  • 一个对象引用可以指向 0 个或 1 个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有 n 个引用指向它(可以用 n 条绳子系住一个气球)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值