Java面试题

1. 自增运算的使用

int i = 1;
i = i++;        //i=1  i++没用
int j = i++;       //j=1  i=2
int k = i + ++i * i++;   //从左往右算i,k = 2 + 3 * 3 | i=4

输出结果: i=4 j=1 k=11

2. println底层的特殊点

  char[]数组的println不是输出地址值,调用的为特定的println(char[] x),此方法会直接将char[]遍历。

int[] arr1 = new int[] {1,2,3};
System.out.println(arr1);  //输出的为地址值
char[] arr2 = new char[] {'a','b','c'};
System.out.println(arr2);  //输出的为abc      所调用的println()方法不同

3. 数组的遍历

  定义一个int[],让数组的每个位置上的值除以首位置的元素,得到的结果作为该位置上的新值。

int[] arr = new int[]{12,22,34,56,43,222,34,30};
for(int i = arr.length - 1;i >= 0;i--){   //应该从后往前遍历,
    arr[i] = arr[i]/arr[0];            //如果从前往后遍历,首位置的元素除完一次就改变了
}

4.重写、重载、多态性的易混淆题目

public class PolymorphismExer {
	public static void main(String[] args) {
		Base base = new Sub();   //多态
		base.add(1,2,3);     //输出结果为sub_1
		Sub sub = new Sub();
		sub.add(1,2,3);     //输出结果为sub_2
	}
}
class Base{
	public void add(int a,int ... arr) {
		System.out.println("base");
	}
}
class Sub extends Base{
	public void add(int a,int[] arr) {  //这是重写,而不是方法的重载
		System.out.println("sub_1");      //因为int[]arr和int...arr不能同时存在
	}                                       //所以编译器认为int[]arr和int...arr是一个东西
	public void add(int a,int b,int c) {
		System.out.println("sub_2");
	}
}

5. == 和 equals() 的区别

  • == 运算符:比较的是栈中的值,所以①对于基本数据类型而言,比较的是数值;②对于引用数据类型而言,比较的是地址值。
  • equals()方法:①只能用于引用数据类型;②Object类中定义的equals()使用的还是 == 运算符,但String、Date、File、包装类等都重写了equals(),使得equals()比较的是属性的相等。

6. 三元运算符易错点

public void test() {
	Object o1 = true?Integer.valueOf(1):Double.valueOf(2.0);
	System.out.println(o1); //输出1.0,三元运算符会自动类型提升,两个类型要求一样
}

7. 包装类的易错点

  Integer类内部通过静态内部类提供了一个缓存池,范围在-128~127之间,如果超过这个范围,Integer值都是new出来的对象。

public void Test() {
	Integer i = Integer.valueOf(1);
	Integer j = Integer.valueOf(1);
	System.out.println(i==j); //true
	Integer x = 1;
	Integer y = 1;
	System.out.println(x==y);  //true
	Integer a = Integer.valueOf(128);
	Integer b = Integer.valueOf(128);
	System.out.println(a==b);  //false
	Integer m = 128;  //Integer类内部通过静态内部类提供了一个缓存池,范围在-128~127之间,
	Integer n = 128;  //如果超过这个范围,Integer值都是new出来的对象
	System.out.println(m==n);  //false
}

8. 接口和继承在属性上的优先级是平行的

interface A{
    int x = 0;
}
class B{
    int x = 1;
}
public class C extends B implements A{
    public void pX() {
        //System.out.println(x);  这样写是错的
        System.out.println(super.x);  //调用B中的x
        System.out.println(A.x);     //调用A中的x
    }
    public static void main(String[] args) {
        new C().pX();
    }
}

9. 接口的注意点

class Ball implements Rollable {
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public Ball(String name) { this.name = name; }
    @Override    //这里的重写即包含了对Playable接口,也包含Bounceable接口的重写
    public void play() {
        //ball = new Ball("Football");  写法是错误的,因为ball已经为final
        System.out.println(ball.getName());
    }
}
interface Playable { void play(); }
interface Bounceable { void play(); }
interface Rollable extends Playable, Bounceable {
    Ball ball = new Ball("PingPang"); //这里隐藏了public static final
}

10. 单例模式

//懒汉式实现单例模式    
class Singleton{    
    private Singleton() {}    
    private static Singleton instance;   
    public static Singleton getInstance(){
        if(instance == null){
            synchronized(Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                } 
            }
        }
        return instance;
    }
} 
//懒汉式单例模式-创建内部类的方式实现
class Singleton{
    private Singleton(){}
    private static class Inner{
        private static final Singleton INSTANCE = new Singleton();
    } 
    public static Singleton getInstance(){
        return Inner.INSTANCE;
    }
}
//饿汉式单例模式
class Singleton{
    private Singleton(){}
    public static final Singleton INSTANCE = new Singleton();
}

11. 类和实例初始化的顺序

在这里插入图片描述
输出结果:(5)(1)(10)(6)(9)(3)(2)(9)(8)(7)
     (9)(3)(2)(9)(8)(7)
     
🔹类初始化
  ①一个类要创建实例需要先加载和初始化该类。
  ②子类要初始化需要先初始化父类。
  ③类的初始化执行的是clinit()方法(即class init);
clinit()方法由静态类变量显示赋值代码和静态代码块组成,执行顺序按照代码编写的位置从上到下执行。

🔸实例初始化
  ①实例初始化是执行init()方法。
  ②init()方法有多个,有几个构造器就有几个init()方法。
  ③init()方法由变量、方法和非静态代码块以及构造器代码组成;
其中变量、方法和非静态代码块按照代码编写的位置从上到下顺序执行,对应的构造器代码最后执行。
  ④init()方法的首行是super(),即对应父类的init()方法。

🔹总结
  父类静态()➡子类静态()➡父类变量方法和非静态()➡父类构造器代码➡子类变量方法和非静态()➡子类构造器代码
  *说明:按照代码编写的位置从上到下顺序执行

12. 方法的参数传递机制

在这里插入图片描述

输出结果:i=1 str=hello num=200 arr=[2,2,3,4] my.a=11

🔸形参是基本数据类型
  传递数据值

🔹引用数据类型
  传递地址值
  特殊的类型:String、包装类具有不可变性

🔸总结
  在方法的参数传递中,基本数据类型传递的是值;String、包装类传递的是地址值,但是无法在原地址上直接修改,修改后的数据是存储在新地址上。

13. 有n步台阶,一次只能上一步或者两步,一共有多少种走法

   𝑓 ( 𝑛 ) = 𝑓 ( 𝑛 − 2 ) + 𝑓 ( 𝑛 − 1 ) 𝑓(𝑛)=𝑓(𝑛−2)+𝑓(𝑛−1) f(n)=f(n2)+f(n1)

//采用递归实现
public static int getFibonacci(int n){
    if(n == 1 || n == 2){
        return n;
    }
    return getFibonacci(n-2) + getFibonacci(n-1);
}
//采用循环迭代实现
public static int getFibonacci(int n){
    if(n == 1 || n == 2){
        return n;
    }
    int step1 = 1;int step2 = 2;int sum = 0;
    for(int i = 3;i <= n;i++){
        sum = step1 + step2;
        step1 = step2;
        step2 = sum;
    }
    return sum;
}

14. 局部变量和成员变量

在这里插入图片描述

运行结果:2,1,5
     1,1,5

🔹局部变量:存储在栈中,只在{}内有效,每次执行都是新的生命周期。

🔸成员变量:分为类变量(static修饰)和实例变量
  类变量存储在方法区中,随着类的创建而初始化,该类的所有对象的类变量都是共享的;
  实例变量存储在堆中,随着对象的创建而初始化,每个对象的实例变量都是独立的。

15. StringBuffer的append

@Test
public void testStringBuffer(){
    String str = null;
    StringBuffer sb  = new StringBuffer();
    sb.append(str);
    System.out.println(sb.length());//4
    System.out.println(sb);//"null"
    StringBuffer sb1 = new StringBuffer(str);//运行抛出异常NullPointerException
    System.out.println(sb1);
}

16. HashSet添加元素的理解

@Test
public void test1(){
    HashSet<Object> hashSet = new HashSet<>();
    Person p1 = new Person(1001, "AA");
    Person p2 = new Person(1002, "BB");
    hashSet.add(p1);
    hashSet.add(p2);
    p1.name = "CC";  //修改了p1的属性,但是p1的哈希值并没有改变
    hashSet.remove(p1);  //使用新的哈希值查找,找不到未更改哈希值的p1
    System.out.println(hashSet);  //输出(1001,"CC")和(1002,"BB")
    hashSet.add(new Person(1001, "CC"));   //能够添加成功
    System.out.println(hashSet);
    hashSet.add(new Person(1001, "AA"));   //虽然哈希值与p1相同,但是equals()匹配的内容不同
    System.out.println(hashSet);  //(1001,"AA")添加成功
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值