第一部分:Java基础
1、什么是 Java 虚拟机?为什么 Java 被称作是“平台无关的编程语言”?
Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程。Java 源文件被编译成能被 Java 虚拟机执行的字节码文件。
一次编译,到处运行(前提:有JVM虚拟机)的原因是:Java是基于虚拟机的语言,它的执行过程是:现经过编译,编译成字节码(.class)文件,在执行的时候通过解释器
将字节码文件根据底层硬件平台的指令长度和其他特性解释成机器语言,之后在运行
2、Java中的名词:JDK,JRE,JVM都是啥
- JDK:JDK是完整的 Java 软件开发包,包含了 JRE,编译器和其他的工具(比如:JavaDoc,Java 调试器),可以让开发者开发、编译、执行 Java 应用程序。
- JRE:JRE是Java运行时的环境,其中包含JVM虚拟机和Java的系统类库(lang包等)
- JVM:JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的(所以它知道底层硬件平台的指令长度和其他特性)。
3、“static”关键字是什么意思?Java 中是否可以覆盖(override)一个 private 或者是 static 的方法?
static字段表示该成员是和类一同加载的,所以可以在没有实例化对象的时候进行访问
Java 中 static 方法不能被覆盖,因为方法覆盖是基于运行时动态(对象实例化时)绑定的,而 static方法是编译时静态绑定的。static 方法跟类的任何实例都不相关,所以概念上不适用。
private字段修饰的方法也不能覆盖,因为,你根本就不知道有这个方法存在
4、是否可以在 static 环境中访问非 static 变量?
不可以,static变量在 Java 中是属于类的,它在所有的实例中的值是一样的。当类被 Java 虚拟机载入的时候,会对 static 变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
5、 Java 支持的数据类型有哪些?什么是自动拆装箱?
- byte
- short
- int
- long
- float
- double
- boolean
- char
自动装箱是 Java 编译器在基本数据类型和对应的对象包装类型之间做的一个转化。比如:把 int 转化成 Integer,double 转化成 double,等等。反之就是自动拆箱。
6、Java 中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?
方法覆盖:子类重写父类的方法(必须有相同的方法名,参数列表和返回类型)
方法重载:在同一个类中,一两个或多个同名方法,形成重载
7、Java 中,什么是构造函数?什么是构造函数重载?
当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。在程序员没有给类提供构造函数的情况下,Java 编译器会为这个类创建一个默认的构造函数。
Java 中构造函数重载和方法重载很相似。可以为一个类创建多个构造函数。每一个构造函数必须有它自己唯一的参数列表。
8、Java 支持多继承么?
Java类不支持多继承。每个类都只能继承一个类,但是可以实现多个接口。
Java的接口可以进行多继承,继承多个接口
9、接口和抽象类的区别是什么?
相同点:
-
都位于继承的顶端,用于被其他类实现或继承;
-
都不能直接实例化对象;
-
都包含抽象方法,其子类都必须覆写这些抽象方法;
区别:
-
抽象类为部分方法提供实现,避免子类重复实现这些方法,提高代码重用性;接口只能包含抽象方法;
-
一个类只能继承一个直接父类(可能是抽象类),却可以实现多个接口;(接口弥补了Java的单继承)
-
抽象类是这个事物中应该具备的你内容, 继承体系是一种 is..a关系
-
接口是这个事物中的额外内容,继承体系是一种 like..a关系
继承类+实现接口 ==> 他是一个人(类),但是他像一个小偷(接口)
二者的选用:
-
优先选用接口,尽量少用抽象类;
-
需要定义子类的行为,又要为子类提供共性功能时才选用抽象类;
10、什么是值传递和引用传递?
对象被值传递,意味着传递了对象的一个副本。因此,就算是改变了对象副本,也不会影响源对象的值。
对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象所做的改变会反映到所有的对象上。
第二部分:线程
1、进程和线程的区别是什么?
进程是执行着的应用程序,而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫做轻量级进程。
2、创建线程有几种不同的方式?你喜欢哪一种?为什么?
方法1:继承Thread类,重写run方法
public class SubThread extends Thread{ public SubThread(){ super("x5456"); //通过构造方法修改线程名 } public void run() { for(int i=0;i<100;i++){ System.out.println(super.getName()+i); } } }
调用
public static void main(String[] args) { //创建刚刚继承Thread类的子类的对象 SubThread st = new SubThread(); //通过setName方法,修改线程名 st.setName("x54256"); //调用对象的start方法,会自动执行我们重写的run方法 st.start(); for(int i=0;i<100;i++) { System.out.println(Thread.currentThread().getName()+i); //获取当前线程的对象,调用getname()方法 } }
方法2:实现接口Runnable,重写run方法
public class SubRunnable implements Runnable{ public void run(){ for(int i=0;i<100;i++){ try { // 调用Thread类的sleep方法,休眠50ms,由于父接口没有throws异常,so我们只能用try...catch Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"..."+i); } } }
调用
public static void main(String[] args) { //创建实现Runnable接口的类的对象 SubRunnable sr = new SubRunnable(); //创建Thread类的对象 Thread t = new Thread(sr); //启动线程 t.start(); for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"..."+i); } }
实现Runnable 接口这种方式更受欢迎,因为这不需要继承 Thread 类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而 Java 不支持多继承),只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。
3、概括的解释下线程的几种可用状态。