Java常见理论面试题

  1. &和&&的区别
    &是与运算符,有0与就是0,也可以作为布尔表达式中的逻辑运算符。
    按位与,逻辑与。
    &&是逻辑运算符,表示短路与。&和&&最大的区别在于短路功能。短路就是指要先满足第一个条件,才会对第二个条件进行判断。

  2. break ,continue ,return 的区别及作用
    (1)break语句用于终止某个语句块的执行,终止本层循环,跳出总的上一层循环,作用是退出当前循环体或者switch代码。
    (2)continue语句只能在循环结构中使用,用于跳出当前循环语句块,终止本次循环,继续下一次循环。
    (3)return语句的作用是结束一个方法,不管return位于哪层循环中,return将结束整个方法。

  3. 在 Java 中,如何跳出当前的多重嵌套循环
    通过给循环添加label标签的方式,选择label后用break跳出指定循环。

  4. final finally finalize区别
    (1)final是一个关键字,一个修饰符。
    1)如果一个类被声明为final类型,意味着它不能派生出子类。
    2)如果一个变量被声明成fianl,就变成了常量,只能在声明的时候赋值一次,之后再引用这个变量时,只能使用,不允许修改。
    3)如果一个方法被声明成final,那么这个方法不能被重写。将变量或者方法声明成final类型,可以保证它们在使用时不被改变。
    abstract是抽象类的关键字,抽象类就是用来给子类继承的,final不能有子类,所以final不能和abstract同时使用。
    (2)finally关键字是用在异常处理时定义finally代码块,finally代码块里面的代码一定会被执行,一般提供finally代码块执行清除操作,比如在IO流的使用时,用于关闭流。
    (3)finalize是一个方法名。在垃圾收集器将对象从内存中清除出去之前,Java 技术允许使用finalize()方法做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的,只能由虚拟机调用这个方法,我们不能在类中调用这个方法。

使用finalize的大致过程:
1)垃圾回收器发现该对象实现了finalize()方法,就会把它添加到引用队列中。
2)Finalize线程会处理这个队列,将里面的对象逐个弹出,并调用finalize()方法。
3)finalize()方法调用完后,Finalize线程会将引用从Finalize类中去掉,因此在一下轮GC中,这些对象就可以被回收了。
4)Finalize线程会和我们的主线程进行竞争,不过它的优先级较低,获取到的CPU时间比较少,因此它永远也赶不上主线程的步伐。

  1. 以小知识点的形式总结(final、访问修饰符)
    static:
    (1)static静态成员变量:
    1)静态属性是属于类的,可以直接使用类名来访问,也可以使用对象访问,但推荐使用类名访问。
    2)类中的静态属性,跟随着类,一起保存在内存中的方法区。
    3)类加载到内存中(方法区)的时候,系统就会给类中的静态属性做初始化赋默认值,就算还没有创建对象,只要这个类加载到了内存,就可以直接使用类名来访问静态属性,因为这个时候静态属性已经完成了初始化赋默认值的操作。
    4)在Java类中,可以用static修饰属性、方法、代码块、内部类。static修饰的方法不能被重写。
    (2)非静态成员变量:
    1)非静态属性,是属于对象的,一定要使用对象来访问。
    2)当创建对象的时候,对象中只会保存类中定义的非静态属性的信息,而静态属性是不会进入到对象中的。
    3)非静态属性创建对象后,系统会自动给对象中的非静态属性做初始化赋默认值,也正是因为这个原因,非静态属性只有在创建对象后,使用对象才能访问。

final:
final修饰符,可以用来修饰类、变量、方法:
(1)用final修饰的类不能被继承,也就是说这个类是没有子类的。
(2)用final修饰的方法可以被子类继承,但是不能被子类的重写。
(3)用final修饰的变量就变成了常量,并且它只能被赋一次值,第二次赋值就会报错。

final修饰不同类型的变量时:
1)final修饰非静态成员变量:JVM不会为其默认赋值,我们需要手动在声明的同时、匿名代码块中、构造器中赋值,并且类中出现的所有构造器都要赋值。
2)final修饰静态成员变量:JVM不会为其默认赋值,需要手动在声明的同时、静态代码块中赋值。
3)final修饰引用类型变量:此时的final指的是,引用s的指向的对象不能改变,但是可以使用s来操作当前指向的对象属性和方法。

abstract:
abstract修饰符,可以修饰类、方法:
(1)如果abstract修饰方法,那么该方法就是抽象方法。抽象方法的特点就是只有方法的声明,没有方法的实现。
(2)如果abstract修饰类,那么该类就是抽象类。抽象类中可以写抽象方法,不能进行实例化创建对象。抽象类中可以没有抽象方法,但抽象方法所在的类一定要声明为抽象类。抽象类就是用来被继承的。抽象类中也有构造器,子类创建对象时要先调用父类的构造器。

interface:
1.接口是除了类和数组之外,另外一种引用数据类型。
2.接口和类不同,类的内部封装了成员变量、构造方法和成员方法,而接口的内部主要就是封装了方法和静态常量。
(1)接口中的属性都是公共的静态常量,常量的名字一般需要全大写。默认是public static final修饰的。
(2)jdk8允许在接口中编写静态方法和默认方法;jdk9允许接口中编写私有方法。
(3)接口中的抽象方法不需要写abstract修饰符,因为接口中的方法默认是抽象方法,默认的修饰符是public abstract。
3.接口的定义和类很类似,但是接口需要使用interface关键字来定义,而类是用class关键字。
4.接口最终也会被编译成.class文件,但一定要明确接口并不是类,而是另外一种引用数据类型。
5.类与类之间的关系是继承,类与接口之间的关系是一个类可以实现一个或多个接口。如果一个类实现了某个接口,就需要把这个接口中的所有抽象方法都实现,否则就要声明成抽象类,让其子类实现抽象方法。

访问修饰符
类中的属性和方法,可以使用以下四种修饰符进行访问控制:public > protected > default > private
public,公共的,在所有地方都可以访问。
protected,受保护的,当前类中、子类中,同一个包中其他类中可以访问。不同包中的非子类就不能访问。
default,默认的,也叫做缺省。当前类中、同一个包中的子类中可以访问。default指的是空修饰符,并不是default这个关键字。其他包的类都不能对其进行访问。
private,私有的,只有当前类中可以访问。

short s1=1;
s1=s1+1;
//有什么错? 

short类型参与运算会自动提升到int类型再进行运算,所以右边s1+1实际上是一个int类型的数据,左边的s1是short类型的数据,大类型转换成小类型要进行强制类型转换。

short s1=1; 
s1+=1;
//有什么错? 

+=运算符使用时,计算机会先把s1隐式转换成int类型,再进行计算,这时声明s1为short类型变得没什么意义。

  1. 面向对象和面向过程的区别。
    (1)面向对象是把构成问题的各种事物抽象成各个对象,这些对象具有解决问题的行为(方法)。同时对象还可以去解决很多类型问题的行为(方法),而不是只能解决一个问题。把面向对象的代码封装起来之后,可以允许其他人使用。
    (2)面向过程是指针对某一个问题,考虑它的解决方案,把解决问题的多个步骤一步步实现,然后依次地调用。

  2. 成员变量与局部变量的区别有哪些
    (1)成员变量:也叫做实例变量或者全局变量。
    定义在类中、方法外,也就是类中的属性,也叫做成员变量(非静态的);不同的类型有不同的默认值;作用范围是当前类中所有的非静态方法中;可以使用修饰符。
    (2)局部变量:定义在方法中的变量;没有默认值;作用范围在当前所处的大括号中;不能使用修饰符。
    (方法的参数(形参)也是局部变量,作用在整个方法中。)

  3. ==和equals的区别是什么?
    ==是一个操作符,不能重写,而且大多被用在基础类型的比较上,因为基本数据类型不能使用equals()方法。

==操作符的本意就是用来比较操作符两边的对象是否是同一个,也就是他们的引用地址一不一样。
equals是个方法,而且是Object的方法,在Java中,所有的类都是Object的子类,故所有对象都有equals()方法。如果没有重写equals()方法的话,那么默认的就是Object的方法,如下:

public boolean equals(Object obj) {
    return (this == obj);
}

显然,其实它的底层也就是进行比较。但是由于是操作符不能重写,equals是方法可以重写,所以就产生了区别。所以就永远比较的是对象地址,而equals在不重写的情况下也是的。所以主要用于基本数据类型的比较,只要基本数据类型的值相等那么就是true,在比较引用的时候则是比较引用的地址值。equals则是主要用在引用对象的比较上,不重写的情况下和==一样,重写就看子类是否需要。

  1. 请编写冒泡排序
package com.briup.day02;
import java.util.Arrays;
/**
 * 1.冒泡排序
 * (1)实现原理:
1.比较相邻的元素,如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素重复上述工作,从第一对到最后一对。完成后,最大的数会放到最后位置。
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
 * (2)冒泡排序的优化:
如果排序进行了几次循环后,排序已经完成,就提前结束循环,不再进行遍历。
 */
public class BubbleSort {
	public static void main(String[] args) {
		BubbleSort sort = new BubbleSort();
		sort.testBubbleSort();
		System.out.println("冒泡排序的优化:");
		sort.testBubbleSort2();
	}
	// 基础冒泡排序
	public void bubbleSort(int[] array) {
		// 待排序元素的个数
		int length = array.length;
		// 如果数组的长度只有一个元素或者没有元素,不需要排序
		if (length <= 1) {
			return;
		}
		/**
		 *  外层循环控制整体排序的次数:
		 * i!=0,不然就多进行一次循环,会导致数组下标越界异常
		 */
		for (int i = 1; i < length; i++) {
			// 相邻比较
			for (int j = 0; j < length - i; j++) {
				//判断前后数据是否需要进行交换,如果前面的数据大于后面的数据,就进行交换,否则不交换
				if (array[j] > array[j + 1]) {
					int temp = array[j];
					array[j] = array[j + 1];
					array[j + 1] = temp;
				}
			}
			// 观察每次排序的结果:
			System.out.println("第" + i + "次排序后:" + Arrays.toString(array));
		}
	}
	public void testBubbleSort() {
		int[] array = new int[] { 7, 2, 1, 9, 0, 3 };
		System.out.println("排序前 : " + Arrays.toString(array));
		// 进行排序
		bubbleSort(array);
		// 输出排序结果
		System.out.println("排序后 : " + Arrays.toString(array));
	}
	public void bubbleSort2(int[] array) {
		int len = array.length;
		if (len <= 1) {
			return;
		}
		for (int i = 1; i < len; i++) {
			// 是否需要提前结束冒泡排序的标识
			boolean flag = true;
			for (int j = 0; j < len - i; j++) {
				if (array[j] > array[j + 1]) {
					int temp = array[j];
					array[j] = array[j + 1];
					array[j + 1] = temp;
					flag = false;
				}
				// 如果排序已经完成,后面就不需要进行遍历
			}
			if (flag) {
				break;
			}
			System.out.println("第" + i + "次排序后:" + Arrays.toString(array));
		}
	}
	public void testBubbleSort2() {
		int[] array = new int[] { 7, 2, 1, 9, 0, 3 };
		System.out.println("排序前 : " + Arrays.toString(array));
		bubbleSort2(array);
		System.out.println("排序后 : " + Arrays.toString(array));
	}
}
  1. 抽象类能使用final修饰吗?
    如果一个类被声明为final类型,意味着它不能派生出子类。而abstract修饰的抽象类就是用来给子类继承的,final不能有子类,所以final不能和abstract同时使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值