Android面试题详解之静态内部类是什么?和非静态内部类的区别是什么?

静态内部类是什么?和非静态内部类的区别是什么?

这道题想考察什么?

掌握static的作用与注意事项

考察的知识点

Java中关键字static

考生应该如何回答

在定义内部类时,如果内部类被static声明,则该内部类为静态内部类。

public class OuterClass{
    
    
    static class InnerClass{
    
    
        
    }
}

当内部类被static声明,那么在内部类中就无法直接使用外部类的属性。比如编写普通内部类:

public class OuterClass{
    
    
    int i;
    public class InnerClass{
    
    
        public InnerClass(){
    
    
            i = 10;
        }
    }
}

此时对OuterClass.java 进行编译,会生成:OuterClass.class 与 OuterClass$InnerClass.class 两个文件。对后者反编译我们将看到:

public class OuterClass$InnerClass {
    
    
    public OuterClass$InnerClass(OuterClass var1) {
    
    
        this.this$0 = var1;
        var1.i = 10;
    }
}

可以看到,普通内部类构造方法中实际上会隐式的传递外部类实例对象给内部类。在内部类中使用外部类的属性:i。实际上是通过外部类的实例对象:var1获取的。同时如果我们需要构建出InnerClass的实例对象,非静态内部类也无法脱离外部类实体被创建。

下面我们将InnerClass定义为static静态内部类:

public class OuterClass{
    
    
    int i;
    public static class InnerClass{
    
    
        public InnerClass(){
    
    
            //i = 10; 
        }
    }
}

此时无法使用外部类的普通成员属性:i。其对应字节码为:

public class OuterClass$InnerClass {
    
    
    public OuterClass$InnerClass() {
    
    
       
    }
}

静态内部类中不再隐式的持有外部类的实例对象。但是如果我们将属性i定义为static,那么在静态内部类中也是可以直接使用外部类的静态成员属性的,此时字节码为:

public class OuterClass$InnerClass {
    
    
    public OuterClass$InnerClass() {
    
    
        OuterClass.i = 10;
    }
}

内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。但是静态内部类能够直接利用new OuterClass.InnerClass() 实例化。

因此静态内部类与非静态内部类的区别有:

  1. 非静态内部类能够访问外部类的静态和非静态成员,静态类只能访问外部类的静态成员。
  2. 非静态内部类不能脱离外部类被创建,静态内部类可以。

2.4 Java中在传参数时是将值进行传递,还是传递引用?

这道题想考察什么?

是否了解什么是值传递和引用传递与真实场景使用,是否熟悉什么是值传递和引用传递在工作中的表现是什么?

考察的知识点

什么是值传递和引用传递的概念,两者对开发中编写的代码的影响

考生应该如何回答

值传递:在方法调用时,传递的参数是这个参数指向值的拷贝;

引用传递:在方法调用时,传递引用的地址

在Java中对于参数的传递可以分为两种情况:

1.基本数据类型的参数

 1 public class TransferTest {
    
    
 2     public static void main(String[] args) {
    
    
 3         int num = 1;
 4         System.out.println("changeNum()方法调用之前:num = " + num);
 5         changeNum(num);
 6         System.out.println("changeNum()方法调用之后:num = " + num);
 7     }
 8 
 9     public static void changeNum(int x) {
    
    
10         x = 2;
11     }
12 }

运行结果:

img

传递过程的示意图如下:

img

分析:num作为参数传递给changeNum()方法时,是将内存空间中num所指向的那个存储单元中存放的值1复制了一份传递给了changeNum()方法中的x变量,而这个x变量也在内存空间中分配的一个存储单元。这时就把num对的值1传递给了x变量所指向的存储单元中。此后在changeNum()方法中对x变量的一切操作都是针对于x所指向的这个存储单元,与num所指向的存储单元无关。

所以,在changeNum()方法被调用后,num所指向的存储单元的值还是没有发生变化,这就是所谓的“值传递”。

值传递的精髓是:传递的是存储单元中的内容,而不是存储单元的引用。

2.引用类型的参数

 1  public class TransferTest2 {
    
    
 2     public static void main(String[] args) {
    
    
 3         Person person = new Person();
 4         System.out.println(person);
 5         change(person);
 6         System.out.println(person);
 7     }
 8 
 9     public static void change(Person p) {
    
    
10         p = new Person();
11     }
12 }
13 
14 /**
15  * Person类
16  */
17 class Person {
    
    
18 
19 }

运行结果:

img

可以看出两次打印结果一致。即调用change()方法后,person变量并没发生改变。

传递过程的示意图如下:

img

分析:

01.当程序执行到第3行 Person person = new Person()时,程序在堆内存(heap)中开辟了一块内存空间用来存储Person类实例对象,同时在栈内存(stack)中开辟了一个存储单元来存储该实例对象的引用,即上图中person指向的存储单元。

02.当程序执行到第5行 change(person)时,person作为参数(实参)传递给了change()方法。这里是person将自己的存储单元的内容传递给了change()方法的p变量。 此后在change()方法中对p变量的一切操作都是针对于p变量所指向的存储单元,与perosn所指向的存储单元就没有关系了。

因此Java的参数传递,不管是基本数据类型还是引用类型的参数,都是按值传递!

更多面试题详解可以扫描二维码免费领取!

猜你喜欢

转载自blog.csdn.net/Misdirection_XG/article/details/131047760