Java 接口和抽象类可以被new么?——顺便总结内部类

2023-05-16

转载:https://blog.csdn.net/hackersaillen/article/details/47281549

背景:

    最近有同事跟我说了他面试时遇到的问题,考官问:“接口和抽象类可以被new嘛?”。这可能不是考官的原话,但是据他表达考官大概就是这个意思了。听到这个问题,我的第一反应是肯定不行啊,直接对接口和抽象类调用new,编译器都过不去。但是他说,考官说可以,用匿名内部类实现。听见这个回到,我感觉那个考官太…………惊讶,有点无语。我们可以仔细分析下这个问题。

 

直接new接口和抽象类

   首先先明确一点,直接new接口和抽象类,这肯定行不通,编译器会提示Cannot instantiate the type XX的错误。这个实验就不做了,没意思。

 

使用匿名内部类

     下面的代码是一个匿名内部类的Demo,也就是考官说的可以new。


   
  1. package com.saillen.test;

  2.  
  3. interface A {

  4. void f();

  5. }

  6.  
  7. public class T {

  8.  
  9. public T(A a) {

  10. a.f();

  11. }

  12.  
  13. public static void main(String[] args) {

  14. T t = new T(new A() {

  15. public void f() {

  16. System.out.println("我是匿名内部类");

  17. System.out.println("Class对象是:" + this.getClass());

  18. System.out.println("类名字是:" + this.getClass().getSimpleName());

  19. }

  20. });

  21. }

  22.  
  23. }

   上面的程序很简单,我们使用匿名内部类,然后“new”一个接口A的对象,输出它的类名了Class对象,输出如下:


   
  1.  
  2. 我是匿名内部类

  3. Class对象是:class com.saillen.test.T$1

  4. 类名字是:

   通过输出可以看到,内部类的类名是“”也就是一个空字符串,但是它确确实实是有类型的。而且查看编译后的class文件,会发现,会多一个T$1.class,这个class就是匿名内部类的原型,

  用javap反编译这个文件,可以看到这个类的源码样式如下:

   通过反编译后的文件可以证明,我们的“匿名内部类”的类名是Test$1。所以new针对的还是普通的class(虽然内部类和普通类有很大不一样),只不过这个class的写法稍有不同,它是编译器帮我们从匿名内部类中提取的。

 

结论:

 通过上面的实验,我仍然坚持,接口和抽象类不可以被new!匿名内部类只是一种写法上的迷惑而已。这个考官的答案很不靠谱,不能说他的想法就是绝对的错,但是绝对不应该这么问这个问题,这不是一个能不能就回答的。或者说不能从字面上就证明可以对interface或者abstract class使用new。

 

内部类总结

    Java编程思想第十章专门介绍了内部类,内部类确实神奇而且复杂。但是内部类在编程中被应用的场景很少,这主要是看设计者的设计思想,不过它的语法和特性却有很多。对于内部类来说要记住可以继承内部类但是不能覆盖

 

普通内部类:

    普通的内部类,就是在class里面普通的定义一个类,eg:


   
  1.  
  2. public class A{

  3. public class B{

  4.  
  5. }

  6.  
  7. }

普通内部类,或者说平凡的内部类,有如下特性:(总结自《Java编程思想》)
   (1)这个类在外部类的外面不能被直接访问,需要通过OuterClassName.InnerClassName方式访问。比如Map的Map.Entry就是一个内部接口,只能通过Map.Entry方式来使用它。

   (2)内部类对象在创建后会秘密的链接到外部类对象上,隐含的有一个指向外部类对象的引用,所以没有外部类对象,是无法实例化内部类对象的。也就是我们无法独立于外部类创建一个内部类对象。(这里不包括声明为static的内部类,那不是平凡的内部类

    (3)因为内部类隐含的有一个指向外部类的指针,所以内部类可以访问外围类的成员,而且是外围类的所有成员,包括private的成员。

    (4)在内部类中使用OuterClassName.this可以访问外围类对象。

    (4)如果想要在外部类外面实例化内部类对象,那么可以同.new语法,也就是outerObject.new InnerClass()的方式,eg:


   
  1.  
  2. package com.saillen.test;

  3.  
  4. public class A {

  5.  
  6. public void f() {

  7. A.B b = this.new B();

  8. B b2 = new B();

  9. }

  10.  
  11. public class B {

  12. void g(){

  13. System.out.println(A.this);

  14. }

  15. }

  16.  
  17. public static void main(String[] args) {

  18. A a = new A();

  19. A.B b = a.new B();

  20. }

  21.  
  22. }

  (5)内部类最大的用途是:它可以实现接口或者继承某个类,这样使用内部类时,用基类引用内部类对象,可以屏蔽内部类的细节。这样的好处是,可以实现伪“多重继承”等。

  (6)普通的内部类不能有static字段和static数据,也不能包含嵌套类。

 

在方法和作用域内的内部类:

   如果内部类出现在了方法和作用域内,那么它就不是“平凡”的内部类了,而且这个内部类的作用域就是在这个方法的作用域内,方法外面是无法访问到的!但是它仍然具有“平凡”的内部类特性。

 

匿名内部类:

   匿名内部类,在内部类的基础上减少了对class的定义,直接用new 后面跟一个接口或者基类,然后类体里面实现方法即可,这样JVM会调用编译器生成的构造器来生成这个内部类对象,并且编译器帮忙生成这个内部类的类结构。匿名内部类好处是语法简单,但是不方便阅读,在Android编程中,对Button的监听经常会用匿名内部类。匿名内部类有一些限制:匿名内部既可以扩展类,也可以实现接口,但是不能两者兼备,而且只能实现一个接口。

 

嵌套类:

   嵌套类就是在内部类的基础上加上static声明,也就是静态的内部类。嵌套类跟普通的内部类特性有很大不同,特点:

   (1)在构造时,不需要外围类的对象,但是同样,它只能访问外围类中的static字段;

   (2)嵌套类可以有static数据和字段;

   (3)嵌套类可以作为接口的一部分,这样在接口中就可以用公用代码出现;

   (4)嵌套类是可以多重嵌套的,嵌套多少层不重要,它都可以访问它所有外围类成员。

 

内部类标识符:

    部类必须生成一个class文件以包含它的Class对象信息,这些类文件有严格的命名规则:外围类的名字,加上“$”,再加上内部类的名字。

 

为什么需要内部类:

   《Java编程思想》中很明确指出:    

   每个内部类都能独立的继承自一个(接口的)实现,所以无论外围类是否已经继承了某个实现,对于内部类都没有影响。

   利用内部类可以实现多重继承等好处,使用内部类还可以实现java版的闭包和回调,而且比指针更灵活、更安全。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 接口和抽象类可以被new么?——顺便总结内部类 的相关文章

  • 从 java sdk 向对等方发送提案时出现访问被拒绝错误

    我正在尝试使用以下代码查询区块链并收到访问被拒绝错误 我也遇到同样的错误sendTransactionProposal方法也是如此 UserContext adminUserContext RegisterEnrollUser regist
  • JPA 中的复合键

    我想创建一个具有自动生成的主键的实体 而且还有一个由其他两个字段组成的唯一复合键 我如何在 JPA 中执行此操作 我想这样做是因为主键应该用作另一个表中的外键 并且使其复合并不好 在下面的代码片段中 我需要命令和模型是唯一的 pk当然是主键
  • 存根方法时出现 InvalidUseOfMatchersException

    我有这个 TestNG 测试方法代码 InjectMocks private FilmeService filmeService new FilmeServiceImpl Mock private FilmeDAO filmeDao Bef
  • Java Runtime.getRuntime().freeMemory() 问题

    我搜索并看到了一些线程 但没有一个能够解决我遇到的具体问题 我正在尝试使用以下方式监视我的内存使用情况Runtime getRuntime freeMemory Runtime getRuntime maxMemory and Runtim
  • 如何在 Firebase 远程配置中从 JSON 获取值

    我是 Android 应用开发和 Firebase 的新手 我想知道如何获取存储在 Firebase 远程配置中的 JSONArray 文件中的值 String 和 Int 我使用 Firebase Remote Config 的最终目标是
  • 是否有任何简单(且最新)的 Java 框架可用于在 Swing 应用程序中嵌入电影?

    我正在构建一个小型 Swing 应用程序 我想在其中嵌入一部电影 重要的是 这个应用程序是一个 WebStart 应用程序 并且该库应该能够打包在我启动的 jnlp 中 即 不依赖于本机库 我知道并尝试过 JMF 但我认为与其他框架相比 其
  • 不同类型的数组

    是否可以有一个包含两种不同类型数据的数组 我想要一个包含双精度型和字符串的数组 我尝试过 ArrayList
  • Integer.parseInt("0x1F60A") 以 NumberformatException 结束

    我尝试从数据库中获取长字符串内的表情符号代码 格式如下 0x1F60A 所以我可以访问代码 但它将是String 起初 我尝试通过执行以下操作来转换变量tv setText beforeEmo getEmijoByUnicode int e
  • 如何在代理后面安装 Eclipse Neon

    对于 Neon Eclipse 附带了一个安装程序 我在安装程序中找不到任何配置菜单 我的java版本是 java version java version 1 8 0 72 Java TM SE Runtime Environment b
  • 什么时候可以在 Java 中使用 Thead.stop() ?

    Thread stop 的 Java 文档听起来好像如果您调用 Thread stop 世界就会终结 已弃用 这种方法本质上是不安全的 停止线程 Thread stop 导致它解锁所有已锁定的监视器 作为未经检查的 ThreadDeath
  • Jackson XML ArrayList 输出具有两个包装器元素

    我在 Jackson 生成的 XML 输出中得到了两个包装器元素 我只想拥有一个 我有一个 Java bean Entity Table name CITIES JacksonXmlRootElement localName City pu
  • 套接字的读写如何同步?

    我们创建一个套接字 在套接字的一侧有一个 服务器 在另一侧有一个 客户端 服务器和客户端都可以向套接字写入和读取 这是我的理解 我不明白以下事情 如果服务器从套接字读取数据 它在套接字中是否只看到客户端写入套接字的内容 我的意思是 如果服务
  • 从 GitHub 上托管的 Spring Cloud Config Server 访问存储库的身份验证问题

    我在 GitHub 上的存储库中托管配置 如果我将回购公开 一切都好 但如果我将其设为私有 我将面临 org eclipse jgit errors TransportException https github com my user m
  • 如何避免 ArrayIndexOutOfBoundsException 或 IndexOutOfBoundsException? [复制]

    这个问题在这里已经有答案了 如果你的问题是我得到了java lang ArrayIndexOutOfBoundsException在我的代码中 我不明白为什么会发生这种情况 这意味着什么以及如何避免它 这应该是最全面的典范 https me
  • 读取电子邮件的文本文件转换为 Javamail MimeMessage

    我有一个电子邮件原始来源的文本文件 直接从 gmail 复制 如果您单击 查看原始文件 您就会看到它 我想读入该文件并将其转换为 MimeMessage 如果您好奇为什么 我设置了 JavaMaildir 并且需要用电子邮件填充它的收件箱以
  • 返回 Java 8 中的通用函数接口

    我想写一种函数工厂 它应该是一个函数 以不同的策略作为参数调用一次 它应该返回一个函数 该函数根据参数选择其中一种策略 该参数将由谓词实现 嗯 最好看看condition3为了更好的理解 问题是 它没有编译 我认为因为编译器无法弄清楚函数式
  • 是否可以使用 Java Guava 将函数应用于集合?

    我想使用 Guava 将函数应用于集合 地图等 基本上 我需要调整 a 的行和列的大小Table分别使所有行和列的大小相同 执行如下操作 Table
  • “无法实例化活动”错误

    我的一个 Android 应用程序拥有大约 100 000 个用户 每周大约 10 次 我会通过 Google 的市场工具向我报告以下异常情况 java lang RuntimeException Unable to instantiate
  • 泛型、数组和 ClassCastException

    我想这里一定发生了一些我不知道的微妙事情 考虑以下 public class Foo
  • 在浏览器刷新中刷新检票面板

    我正在开发一个付费角色系统 一旦用户刷新浏览器 我就需要刷新该页面中可用的统计信息 统计信息应该从数据库中获取并显示 但现在它不能正常工作 因为在页面刷新中 java代码不会被调用 而是使用以前的数据加载缓存的页面 我尝试添加以下代码来修复

随机推荐