Java中的内部类,java开发工程师常见面试题

HarmonyOS学习 2021-11-25 19:18:16
java 面试 编程语言 后端开发

public class Parcel{

class Contents{

private int i = 11;

public int value(){ return i;}

}

public Contents contents(){

return new Contents();

}

public static void main(String[] args){

Parcel p = new Parcel();

Parcel.Contents c = p.contents();

}

}

其实上使用内部类与使用普通类相比较没有什么不同,但是因为内部类是嵌套在类中的,我们可以在外部类中定义一个方法用来返回内部类中的引用。如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须像在main()方法中那样,具体地指明这个对象的类型:OuterClassName.InnerClassName

1.2 链接到外部类

内部类似乎只是一种名字隐藏和组织代码的模式;当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了一种联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。

内部类还拥有其外围类的所有成员的访问权,内部类的对象只能在与其外围类的对象相关联的情况下才能被创建。构建内部类对象时,需要一个指向其外围类对象的引用,如果编译器访问不到这个引用就会报错。

1.3 生成对外部类对象的引用

如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟 .this。这样产生的引用自动具有正确的类型,这一点在编译期就被知晓并受到检查,因此没有任何运行时开销。

在外部使用内部类的两种方式:

1.3.1 在外围类中定义一个方法,该方法返回内部类的一个对象,方法是public的

public class DotThis{

void f(){

System.out.println(“DotThis.f()”);

}

public class Inner{

public DotThis outer(){

return DotThis.this;

}

}

public Inner inner(){

return new Inner();

}

public static void main(String[] args){

Dot

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

This dt = new DotThis();

DotThis.Inner dti = dt.inner();

dti.outer().f();

}

}

1.3.2 用外围类的对象得到内部类对象

有时候你可能想要告知某些其他对象,去创建其某个内部类的对象。要实现此目的,你必须在new表达式中提供对其他外部类对象的引用,这时需要使用 .new语法:

public class DotNew{

public class Inner{}

public static void main(String[] args){

DotNew dn = new DotNew();

DotNew.Inner dni = dn.new Inner();

}

}

要想直接创建内部类的对象,不能去引用外部类的名字DotNew,而是必须使用外部类的对象来创建该内部类对象。这也解决了内部类名字作用域的问题,因此你不必声明,dn.new DotNew.Inner()

在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗地连接到创建它的外部类对象上。但是,如果你创建的是嵌套类(静态内部类),那么它就不需要对外部类对象的引用。

1.4 内部类与向上转型

当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地。这是因为此内部类–某个接口的实现–能够完全不可见,并且不可用。所得到的只是指向基类或接口的引用,所以能够很方便地隐蔽实现细节。

public interface Destination{

String readLabel();

}

public interface Contents{

int value();

}

现在ContentsDestination表示客户端程序员可用的接口。当取的得了一个指向基类或接口的引用时,甚至可能无法找出它确切的类型:

class Parcel{

private class PContents implements Contents{

private int i =11;

public int value(){return i;}

}

protected class PDestination implements Destination{

private String label;

private PDestination(String whereTo){

label = whereTo;

}

public String readLabel(){ return label;}

}

public Destination destination(String s){

return new PDestination(s);

}

public Contents contents(){

return new PContents();

}

}

public class TestParcel{

public static void main(String[] args){

Parcel p = new Parcel();

Contents c = p.contents();

Destination d = p.destination(“Tasmania”);

}

}

Parcel中增加了一些新东西:内部类PContentsprivate,所以除了Parcel,没人能访问它。PDestinationprotected,所以只有Parcel及其子类、还有与Parcel同一个包中的类能访问PDestination,其他类都不能访问PDestination。这意味着,如果客户端程序员想了解或访问这些成员,那是受限制的。

private内部类给类的设计者提供了一种途径,通过这种方式可以完全组织任何依赖于类型的编码,并且完全隐藏了实现的细节。此外,从客户端程序员的角度来看,由于不能访问任何新增加的、原本不属于公共接口的方法,所以扩展接口是没有价值的。这也给Java编译器提供了生成更高效代码的机会。

 内部类分类


上边已经简单介绍了内部类的使用,除了作为外部类的一个成员存在的内部类(成员内部类)以外还有其他形式的内部类:局部内部类、匿名内部类

2.1 局部内部类

在Java中,可以在一个方法里面或者在任意的作用域内定义内部类。这么做的两个理由:

  • 1.实现了某类型的接口,于是可以创建并返回对其的引用。

  • 2.需要解决一个复杂的问题,想创建一个类来辅助解决方案,但是又不希望这个类是公共可用的。

在方法的作用域内创建一个完整的类,这称作局部内部类

public class Parcel5{

interface Destination{}

public Destination destination(String s){

class PDestination implements Destination {

private String label;

private PDestination(String whereTo) {

label = whereTo;

}

public String readLabel(){return label;}

}

return new PDestination(s);

}

public static void main(String[] args) {

Parcel5 p = new Parcel5();

Destination d = p.destination(“Tasmania”);

}

}

在任意的作用域内嵌入一个内部类:

public class Parcel6 {

private void internalTracking(boolean b){

if(b){

class TrackingSlip{

private String id;

TrackingSlip(String s){

id=s;

}

String getSlip(){return id;}

}

TrackingSlip ts=new TrackingSlip(“slip”);

String s=ts.getSlip();

}

}

public void track(){

internalTracking(true);

}

public static void main(String[] args) {

Parcel6 p=new Parcel6();

p.track();

}

}

当我们需要一个已命名的构造器,或者需要重载构造器时我们会用到局部内部类,而不能使用匿名内部类,因为匿名内部类只能用于实例初始化。当我们需要不止一个该内部类的对象,也要采用局部内部类。

局部内部类不能有访问说明符,因为它不是外围类的一部分;但是它可以访问当前代码块内的常量,以及此外围类的所有成员。局部内部类的名字在方法外是不可见的。

2.2 匿名内部类

public class Parcel {

interface Contents {}

// class MyContents implements Contents {

// private int i=11;

// public int value(){return i;}

// }

public Contents contents() {

return new Contents() {

private int i = 11;

public int value() {return i;}

};

// return new MyContents();

}

public static void main (String[]args){

Parcel p = new Parcel();

Contents c = p.contents();

}

}

创建一个继承自Contents的匿名类的对象,在这个匿名内部类中,使用了默认的构造器来生成Contents。如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数是final的。否则,编译器将会报错。如果只是传递给匿名类的基类的构造器,那么不需要将传入的形参定为final(匿名内部类没有构造器,只能用实例化代替。)

2.3 嵌套类

如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。这通常称为嵌套类。普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象。然而,当内部类是static的时,就会不一样了。嵌套类意味着:

  • 1.要创建嵌套类的对象,并不需要其外围类的对象

  • 2.不能从嵌套类的对象中访问非静态的外围类对象

嵌套类与普通的内部类还有一个区别,普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。

接口内部的类:

正常情况下,不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分。你放到接口中的任何类都自动地是public和static的。因为类是static的,只是将嵌套类置于接口的命名空间内,这并不违反接口的规则。你甚至可以在内部类中实现其外围接口:

public interface ClassInInterface{

void howdy();

class Test implements ClassInInterface{

public void howdy(){

System.out.print(“Howdy!”);

public static void main(String[] args){

new Test().howdy();

}

}

如果你想要创建某些公共代码,使得它们可以被某个接口的所有不同实现所共用,那么使用接口内部的嵌套类会显得很方便。

嵌套类的两个有效用途:

  • 1.实现每个类实现接口都需要一部分公共代码

  • 2.代替main方法对每个类进行测试

最后

最后,强调几点:

  • 1. 一定要谨慎对待写在简历上的东西,一定要对简历上的东西非常熟悉。因为一般情况下,面试官都是会根据你的简历来问的; 能有一个上得了台面的项目也非常重要,这很可能是面试官会大量发问的地方,所以在面试之前好好回顾一下自己所做的项目;
  • 2. 和面试官聊基础知识比如设计模式的使用、多线程的使用等等,可以结合具体的项目场景或者是自己在平时是如何使用的;
  • 3. 注意自己开源的Github项目,面试官可能会挖你的Github项目提问;

我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!

以上面试专题的答小编案整理成面试文档了,文档里有答案详解,以及其他一些大厂面试题目。

面试答案

Java中的内部类,java开发工程师常见面试题_Java

Java中的内部类,java开发工程师常见面试题_面试_02

Java中的内部类,java开发工程师常见面试题_面试_03

本文已被 CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

版权声明
本文为[HarmonyOS学习]所创,转载请带上原文链接,感谢
https://blog.51cto.com/u_15438507/4690530

  1. Fonction de flèche JavaScript
  2. JavaScript - déconstruction assignations
  3. Building CentOS 7.6 with Linux
  4. JavaScript - type d'emballage
  5. linux deepin/ubuntu安装flameshot火焰截图
  6. JavaScript - encapsulation et héritage (deux)
  7. JavaScript JS method for writing 99 multiplication table
  8. 從零開始學java - 第二十五天
  9. Apprendre Java à partir de zéro - jour 25
  10. Les voitures d'hiver, les voitures électriques et les voitures à essence ne sont pas les mêmes?
  11. JavaScript - ceci pointe vers le problème
  12. Copie JavaScript
  13. Spring boot quickly integrates swagger
  14. linux deepin/ubuntu安裝flameshot火焰截圖
  15. Capture d'écran de flamme de l'installateur de flamme Linux deepin / Ubuntu
  16. Jquery DOM et jquery, fonctions d'entrée (bases)
  17. Méthode d'instance jquery
  18. Méthode et démonstration de code dans l'interface de liste en Java
  19. 【错误记录】Java 中 ArrayList 排序 ( 使用 Comparator 接口时注意 compare 返回值是 -1 和 +1 )
  20. Démarrage du Zookeeper
  21. Java oom Cognition
  22. Java 开发者最困惑的四件事,值得一看!,BAT面试文档
  23. Java 将两个对象list里面的 某个字段值抽取到一个list里,java选择排序原理
  24. Java 多线程 —— 生产者消费者问题,从基础到深入案例
  25. Java 中设计模式 之 工厂模式,java反射机制的底层原理
  26. 【錯誤記錄】Java 中 ArrayList 排序 ( 使用 Comparator 接口時注意 compare 返回值是 -1 和 +1 )
  27. 【 enregistrement des erreurs 】 tri ArrayList en Java (Notez que les valeurs de retour de comparaison sont - 1 et + 1 lors de l'utilisation de l'interface de comparaison)
  28. Pourquoi Xiaopeng P5 est - il devenu un grand succès dans le cercle? Le Salon de l'automobile de Guangzhou montre encore des compétences polyvalentes
  29. Java 開發者最困惑的四件事,值得一看!,BAT面試文檔
  30. Les quatre choses les plus déroutantes pour les développeurs Java valent la peine d'être regardées! Document d'entrevue sur les MTD
  31. k8s-Pod污点与容忍
  32. k8s-Pod污点与容忍
  33. K8s POD Contamination and Tolerance
  34. K8s POD Contamination and Tolerance
  35. mysql常用语句——GROUP BY和HAVING
  36. Spring boot quickly integrates swagger
  37. mysql常用語句——GROUP BY和HAVING
  38. MySQL Common statements - group by and having
  39. Le défi du pinceau leetcode - Javascript: 110. Arbre binaire équilibré
  40. [notes d'apprentissage de première ligne] day44: XMLHttpRequest
  41. java调用RFC延长调用时间
  42. java調用RFC延長調用時間
  43. Java call RFC prolonge le temps d'appel
  44. Le modèle d'usine du modèle de conception en Java, le principe sous - jacent du mécanisme de réflexion Java
  45. Java Multithreading - producer Consumer issues, From Basic to Deep case
  46. OushuDB 安装与升级之安装 HDFS
  47. OushuDB 安装与升级之安装 Zookeeper
  48. Java-String-对象,你真的了解了吗?,mysql教程入门到精通
  49. Linux引导过程与服务控制
  50. Java-8新特性:学习如何使用Lambda表达式(一,线程池的实现原理
  51. Java 读写锁 ReentrantReadWriteLock 源码分析,headfirstjavapdf百度云
  52. JAVA 获取系统日期时间,初级java开发常见的面试题
  53. MySQL judges the salary changes based on the existing data
  54. k8s-Pod污點與容忍
  55. Java extrait une valeur de champ de deux listes d'objets dans une liste, et Java sélectionne le principe de tri
  56. java中ArrayList应用实例,阿里巴巴java面试流程
  57. Java个人技术知识点总结(框架篇),kafka聊天服务器架构
  58. JavaWeb快速入门--Servlet(2),java程序设计精编教程第三版上机实践
  59. JavaWeb - 文件的上传,核心API的使用,文件下载,附学习笔记 面试整理 进阶书籍
  60. Netty原理:pipeline