首页 > 编程语言 >【Android面试】2023最新面试专题四:Java核心基础(上)

【Android面试】2023最新面试专题四:Java核心基础(上)

时间:2023-06-19 14:03:59浏览次数:39  
标签:InnerClass Java equals public 面试 2023 OuterClass 方法 class


1 Java中提供了抽象类还有接口,开发中如何去选择呢?

这道题想考察什么?

Java是面向对象编程的,抽象是它的一大特征,而体现这个特征的就是抽象类与接口。抽象类与接口某些情况下都能够互相替代,但是如果真的都能够互相替代,那Java为何会设计出抽象与接口的概念?这就需要面试者能够掌握两者的区别。

考察的知识点

OOP(面向对象)编程思想,抽象与接口的区别与应用场景;

考生应该如何回答

抽象类的设计目的,是代码复用;接口的设计目的,是对类的行为进行约束。

  • 当需要表示is-a的关系,并且需要代码复用时用抽象类
  • 当需要表示has-a的关系,可以使用接口

比如狗具有睡觉和吃饭方法,我们可以使用接口定义:

public interface Dog {
	public void sleep();
	public void eat();
}

但是我们发现如果采用接口,就需要让每个派生类都实现一次sleep方法。此时为了完成对sleep方法的复用,我们可以选择采用抽象类来定义:

public abstract class Dog {
    public void sleep(){
        //......
    }
	public abstract void eat();
}

但是如果我们训练,让狗拥有一项技能——握手,怎么添加这个行为? 将握手方法写入抽象类中,但是这会导致所有的狗都能够握手。

握手是训练出来的,是对狗的一种扩展。所以这时候我们需要单独定义握手这种行为。这种行为是否可以采用抽象类来定义呢?

public abstract Handshake{
    abstract void doHandshake();
}

如果采用抽象类定义握手,那我们现在需要创建一类能够握手的狗怎么办?

public class HandShakeDog extends Dog //,Handshake

大家都知道在Java中不能多继承,这是因为多继承存在二义性问题。

二义性问题:一个类如果能够继承多个父类,那么如果其中父类A与父类B具有相同的方法,当调用这个方法时会调用哪个父类的方法呢?

所以此时,我们就需要使用接口来定义握手行为:

public interface Handshake{
    void doHandshake();
}
public class HandShakeDog extends Dog implements Handshake

不是所有的狗都会握手,也不止狗会握手。我们可以同样训练猫,让猫也具备握手的技能,那么猫Cat类,同样能够实现此接口,这就是"has-a"的关系。

抽象类强调从属关系,接口强调功能,除了使用场景的不同之外,在定义中的不同则是:

【Android面试】2023最新面试专题四:Java核心基础(上)_面试

2 重载和重写是什么意思,区别是什么? (京东)

这道题想考察什么?

Java基础

考察的知识点

面向对象多态的基础概念

考生应该如何回答

重写(Override)

重写就是重新写的意思,当父类中的方法对于子类来说不适用或者需要扩展增强时,子类可以对从父类中继承来的方法进行重写。

比如Activity是Android开发中四大组件之一。在Activity中存在各种声明周期方法:onCreate、onStart …等等。而我们应用中需要使用Activity来展示UI,那么我们会需要编写自己的类继承自Activity。

public class MainActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

在上述代码中,onCreate就是被我们重写的Activity中定义方法。我们在onCreate增加了setContentView

的调用,完成了对超类Activity中对应方法的修改与扩展。

重载(Overload)

重载则是在同一个类中,允许存在多个同名方法,只要它们的参数列表不同即可。比如在Android开发中,我们会使用LayoutInflater的inflate方法加载布局,inflate方法存在多个定义,其中包括两个参数的,与三个参数的:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
	return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
    //......
}

可以看到在两个参数的inflate方法中,会为我们调起三个参数的inflate方法,而定义第一个inflate方法的目的就是为了提供默认的attachToRoot参数值。因为Java中无法定义方法参数默认值,所以我们经常使用重载达成此目的。


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

这道题想考察什么?

掌握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. 非静态内部类不能脱离外部类被创建,静态内部类可以。

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 }

运行结果:

【Android面试】2023最新面试专题四:Java核心基础(上)_外部类_02

传递过程的示意图如下:

【Android面试】2023最新面试专题四:Java核心基础(上)_内部类_03

分析: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 }

运行结果:

【Android面试】2023最新面试专题四:Java核心基础(上)_内部类_04


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

传递过程的示意图如下:

【Android面试】2023最新面试专题四:Java核心基础(上)_面试_05


分析:

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

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

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

5 使用equals和==进行比较的区别

这道题想考察什么?

在开发中当需要对引用类型和基本数据类型比较时应该怎么做,为什么有区别。

考察的知识点

equals 的实现以及栈和堆的内存管理。

考生应该如何回答

==

对于不同的数据类型,使用==进行比较的意义不同:

  • 基本数据类型(也称原始数据类型) :byte,short,char,int,long,float,double,boolean。用==,比较的是他们的值;
  • 引用数据类型:用(==)进行比较的时候,比较的是地址。

对于引用类型,除非是同一个new出来的对象,他们的比较的结果为true,否则为false。因为每new一次,都会重新开辟堆内存空间,哪怕他们的值一致,但是也是在不同的地址存放。所以对于引用类型的值比较应该使用equals方法。

equals()方法介绍

equals 方法是 Object 中定义的一个方法,源码如下:

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

可以看到实际上就是用的 == 实现的,所以这个原始方法意义不大,一般在类中做比较的时候,都会重写这个方法,如String、Integer、Date等。

//Integer
public boolean equals(Object obj) {
	if (obj instanceof Integer) {
        //比较Integer中包装的int值
		return value == ((Integer)obj).intValue();
	}
	return false;
}
//String
public boolean equals(Object anObject) {
	if (this == anObject) { //同一个对象
		return true;
	}
	if (anObject instanceof String) {
		String anotherString = (String)anObject;
		int n = length();
		if (n == anotherString.length()) {
			int i = 0;
			while (n-- != 0) {
				if (charAt(i) != anotherString.charAt(i))  //逐个字符比较
					return false;
				i++;
			}
			return true;
		}
	}
	return false;
}

String的比较

public class StringDemo {
    public static void main(String args[]) {
        String str1 = "Hello";
        String str2 = new String("Hello");
        String str3 = str2; // 引用传递
        System.out.println(str1 == str2); // false
        System.out.println(str1 == str3); // false
        System.out.println(str2 == str3); // true
        System.out.println(str1.equals(str2)); // true
        System.out.println(str1.equals(str3)); // true
        System.out.println(str2.equals(str3)); // true
    }
}

栈和堆的内存分析图:

【Android面试】2023最新面试专题四:Java核心基础(上)_内部类_06

由此可见,equals 是比较字符串的内容是否一样,== 是比较字符串的堆内存地址是否一样。

结论

equals和==的区别,需要分情况讨论:

  1. 没有重写 equals ,则 equals 和 == 是一样的。
  2. 如果重写了 equals,则需看 equals 的方法实现。以 String 类为例:
  1. equals 是比较字符串的内容是否一样;
  2. == 是比较字符串的堆内存地址是否一样,或者说引用的值是否相等。


标签:InnerClass,Java,equals,public,面试,2023,OuterClass,方法,class
From: https://blog.51cto.com/u_16163442/6512809

相关文章

  • 在 JavaScript 中,判断一个对象是否为空有几种方法。
    使用Object.keys()方法检查对象的键值对数量:functionisObjectEmpty(obj){returnObject.keys(obj).length===0;}//示例用法constobj1={};console.log(isObjectEmpty(obj1));//输出:trueconstobj2={name:'John',age:25};console.log(isObjectEm......
  • 强化学习从基础到进阶-常见问题和面试必知必答[1]:强化学习概述、序列决策、动作空间
    强化学习从基础到进阶-常见问题和面试必知必答[1]:强化学习概述、序列决策、动作空间定义、策略价值函数、探索与利用、Gym强化学习实验1.强化学习核心概念强化学习(reinforcementlearning,RL):智能体可以在与复杂且不确定的环境进行交互时,尝试使所获得的奖励最大化的算法。动......
  • 2023.6.19 可被3整除的最大和
    考虑动态规划,令f[i][j]表示以i开始,模3后值为j的最大和。那么可以得到状态转移方程:不取当前数,f[i][j]=f[i+1][j]取当前数,f[i][(f[i+1][j]+nums[i])%3]=f[i+1][j]+nums[i]目标状态:f[0][0]implSolution{pubfnmax_sum_div_three(nums:Vec<i32>)->......
  • API接口开发系列(获得京东JD商品详情原数据java源代码调用示例)
    请求获取京东商品详情原数据(免费获取调用请私信)的作用:1.提供商品信息:京东商品详情中的原数据可以提供商品的基本信息,包括商品名称、价格、品牌、规格参数、图片等,让消费者更好地了解商品。2.帮助搜索引擎识别:京东商品详情的原数据可以被搜索引擎识别,在搜索结果页中显示更为详细丰富......
  • 【Android面试】2023年Android中高级最全面试题,轻松拿offer
    前言2023年的金三银四来了,不知道大家准备好了没?对于程序员而言,无论是想加快个人技能成长速度,或是想要升职涨薪,都需要不断进阶,跳槽到规模与业务更大、并且有成熟的技术成长体系的公司当中去。而想要跳槽成功,面试可以说是决定性因素。这里给大家整理了一份935页的《2023年Android中高......
  • 2023 年第一弹, Flutter 3.7 发布啦,快来看看有什么新特性
    2023年新春之际,Flutter喜提了3.7的大版本更新,在Flutter3.7中主要有改进框架的性能,增加一些很棒的新功能,例如:创建自定义菜单栏、级联菜单、更好地支持国际化的工具、新的调试工具等等。另外Flutter3.7还改进了Globalselection、使用Impeller提升渲染能力、DevTools等......
  • SprintBoot JavaWeb访问提示 Full authentication is required to access this resour
    SprintBoot部署好网站之后访问没有异常,但是配置域名地址至Nginx上时登录请求报错了,经查询是因为项目是前后端分离,请求的路由会加上工程的主路径,所以需要在Nginx多配置一个地址,如Location/{http://localhost:8080/project}location/project/{http://loc......
  • 2022最新 Android 中高级面试题汇总(含答案解析)
    准备面试少不了Android面试题复习,面试题也需要有方法,高效的进行复习,所以给大家分享一份《2022最新Android中高级面试题汇总》,基本涵盖了Android中高级工程师面试必备知识点,希望可以帮助一些想要跳槽涨薪的朋友更好、更高效的复习,实现跳槽涨薪。Android中高级面试题主要包含知识......
  • JavaScript 显示数据
    JavaScript显示数据JavaScript可以通过不同的方式来输出数据:使用window.alert()弹出警告框。使用document.write()方法将内容写到HTML文档中。使用innerHTML写入到HTML元素。使用console.log()写入到浏览器的控制台。window.alert()window.alert()是一个......
  • 使用Kotlin+Rretrofit+rxjava+设计模式+MVP封装网络请求
    0、前言:kotlin使用起来非常顺畅,尤其是结合rxjava、设计模式使用,你会发现写代码原来可以这么开心!什么?你还在使用java?赶紧去学一下kotlin吧!我相信你一定会对他爱不释手,kotlin也很容易学,花一天的时间就可以从java切换为kotlin一、正文本文主要介绍如何使用kotlin封装网络请求的工具,结......