Java语法汇总二(NK)(更新至2021.10.29)

汇总一链接:Java语法汇总一(NK)

目录

41. 什么是web容器

42. java.lang包是java语言的核心包

43. JAVA的垃圾回收机制 

44. Integer类的parseInt()方法

45. 迭代器Iterator

46. Java Thread的start()和run()

47. 使线程释放锁的几种操作

48. 内部类的几个知识点

49. Java语言的静态多分派,动态单分派

50. 类的加载包括:加载,验证,准备,解析,初始化

51. Java构造方法的知识点

52. AOP的知识点

53. 数组的6种表示方式

54. 泛型的知识点

55. Java程序的执行过程

56. 一个.java文件中定义几个类的问题

57. 抽象类和接口的区别

58. Java中的“|” 和“||”

59. 三元操作符的转换规则

60. 8种基本类型的大小,封装类,默认值,范围等

61. 什么是对象的序列化

62. ThreadLocal类

63. 关于Servlet的知识点

64. Java的异常Exception的常见类型

65. JavaWEB中的多个会话监听类,如HttpSessionListener等

66. 后端向前端传输数据的安全性问题, XSS过滤器

67. Java中的“==”和equals的问题点

68. 复制数组的几种方法和效率高低

69. 字母和整数对应的ASCII码值,快速记忆

70. subSet() 和 subList()

71. Off-heap 堆外内存

72. HttpServlet容器响应Web客户请求的流程

73. 事务隔离级别的相关概念

74. 抽象类 (abstract) 和 最终类 (final)

75. Object类的一些常用方法

76. Java内部类


41. 什么是web容器

 (1)web容器是一种服务程序。

在服务器的一个端口就有一个提供相应服务的程序,这个程序处理从客户端发出的请求。

如Java中的tomcat容器,ASP的IIS或PWS容器。

一个服务器可以有多个容器。

(2)web容器,例如tomcat,用于接受,响应客户端的请求,负责将HTTP请求转化为HttpServletRequest对象,也就是常见servlet实例对象。

补:

(3)http:HTTP协议,是用于从WWW服务器传输超文本到本地浏览器的传输协议。

(4)servlet:是一套技术标准,内含与web应用相关的一系列接口,用于为web应用实现方式提供宏观解决方案。

(5)jsp网页:java的服务器页面,其本质也是一个servlet,由html网页代码,Java代码,jsp标签组成,当servlet处理完数据后会转发给jsp,jsp负责显示数据。

补:

(1)在Web应用程序的文件与目录结构中,web.xml是用来初始化配置信息的,放置在WEB-INF目录中。

42. java.lang包是java语言的核心包

(1)java.lang包定义了一些基本类型,包括Integer,String之类的,是java程序必备的包,由解释器自动引入,无需手动导入。

43. JAVA的垃圾回收机制 

(1)java提供一个系统级的线程,即垃圾回收器线程。

用来对每一个分配出去的内存空间进行跟踪。

当JVM空闲时,自动回收每块可能被回收的内存。

GC是完全自动的,不能被强制执行。

程序员最多只能用System.gc()来建议执行垃圾回收器回收内存,但具体的回收时间是不可知的。当对象的引用变量被赋值为null,可能被当成垃圾。

(2)垃圾回收在jvm中的优先级相当低。

(3)垃圾回收机制只是回收不再使用的JVM内存,如果程序有严重的bug, 照样内存溢出。

(4)进入DEAD的线程,它还可以恢复,GC不会回收。

44. Integer类的parseInt()方法

(1)parseInt(): 将字符串参数解析为带符号的十进制整数。

(2)字符串中的字符都必须是十进制数,除了第一个字符可能是ASCII减号(‘-’, ‘\u002D’)以指示负值,或加号('+', '\u002B')以指示正值。

(3)返回得到整数值。

(4)非纯数字的字符串转化为Integer对象会报错,比如:String str = " 123456as"; int num = Integer.parseInt(str) 会报“java.lang.NumberFormatException”的错。

45. 迭代器Iterator

(1).hasNext()

(2).next()

(3).remove():Iterator支持从源集合中安全的删除对象,只要在Iterator实例上调用remove()即可。好处是可以避免ConcurrentModifiedException, 当打开Iterator迭代集合时,同时又对集合做修改。有些集合不允许在迭代时删除或添加元素,但是调用Iterator的remove()方法是个安全的办法。it.remove(),无参,it是it=list.Iterator();

46. Java Thread的start()和run()

(1)start()方法:用来启动线程,是真正的实现了多线程。通过调用start()方法来启动一个线程,这时候线程处于就绪(可运行)状态,并没有运行。一旦得到cpu时间片,就开始执行run()方法。

注意:此时无需等待run()方法执行完毕,即可继续执行下面的代码。所以run()方法并没有实现多线程。

(2)run()方法:只是类的一个普通方法而已,如果直接调用run()方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run()方法体执行完毕后才可继续执行下面的代码。

补:

(1)最常用的同步器有:CountDownLatch, Semaphore。不常用的是:Barrier, Exchanger。

(1)CyclicBarrier和CountDownLatch都可以让一组线程等待其他线程。前者是让一组线程相互等待到某一个状态再执行,后者是一个线程等待其他线程结束再执行。

(2)Callable中的call()方法,比Runnable中的run()厉害在有返回值和可以抛出异常。同时这个返回值和线程池一起用的时候可以返回一个异步对象Future。

47. 使线程释放锁的几种操作

(1)wait():释放。会使当前线程回到线程池中等待,释放锁,当被其他线程使用notify, notifyAll唤醒时,进入可执行状态。

(2)join():释放。当前线程调用某线程的.join()时,会使当前线程等待某线程执行完毕再结束,底层调用了wait(),释放锁。

(3)sleep():不释放。会使当前线程睡眠指定时间,不释放锁。

(4)yield():不释放。会使当前线程重回到可执行状态,等待cpu的调度,不释放锁。

补:

(1)一个线程调用yield方法(休眠),可以使具有相同优先级的线程获得处理器。

通俗的说,yield方法比较高尚,让同级的其他线程先获得处理器。

因此,yield()的目的是让具有相同优先级的线程之间能够适当的轮换执行。

但是实际中无法保证yield()达到让步的目的,因为让步的线程有可能再次被线程调度程度调度。

48. 内部类的几个知识点

(1)静态内部类才可以声明静态方法

(2)静态方法不可以使用非静态变量

49. Java语言的静态多分派,动态单分派

(1)如果是重载方法之间的选择,则是使用静态类型。

重载中,运用静态多分派,即根据静态类型确定对象,因此不是根据new的类型确定调用方法。

(2)如果是父类与子类之间的重写方法的选择,则是使用动态类型。

如A a = new B(); 会使用B类型去查找重写的方法,使用A类型去找重载的方法。

重写中,运用的是动态多分派,是根据new的类型确定对象,从而确定调用的方法。

50. 类的加载包括:加载,验证,准备,解析,初始化

51. Java构造方法的知识点

(1)不能被这些修饰: final,static,synchronized, native

构造方法不能被子类继承,所以用final没有意义。

构造方法用于创建一个新的对象,不能作为类的静态方法,所以用static没有意义。

java语言不支持native, synchronized修饰的构造方法。

(2)不需要同步化。(补:子类可以覆盖掉父类的同步方法)

(3)优先级一般比代码块低

(4)主要作用是完成对类的对象的初始化工作

(5)一般在创建新对象时,系统会自动调用构造方法

(6)构造方法没有返回值,也不返回void (注意区分,有的方法跟类名同名,但是有返回值类型,这个就不是构造方法,而是一般的方法)

52. AOP的知识点

(1)AOP将散落在系统中的“方面”代码集中实现。

(2)AOP有助于提高系统可维护性。

(3)AOP是一种设计模式,Spring提供了一种实现。

53. 数组的6种表示方式

(1)float a[][] =  new float[6][]

(2)float a[][] = new float[6][6]

(3)float []a[] = new float[6][]

(4)float []a[] = new float[6][6]

(5)float [][]a = new float[6][]

(6)float[][]a = new float[6][6]

54. 泛型的知识点

(1)创建泛型对象时,一定要指出类型变量T的具体类型,争取让编译器检查出错误,而不是留给JVM运行时抛出类不匹配的异常。

(2)JVM如何理解泛型概念?答:类型擦除

事实上,JVM不知道泛型,所有的泛型在编译阶段就已经被处理成了普通类和方法。

处理方法很简单,我们称之为类型变量T的擦除(erased)。

泛型代码和JVM:

1)虚拟机没有泛型,只有普通类和方法

2)在编译阶段,所有泛型类的类型参数都会被Object或他们的限定边界来替换。即类型擦除。

3)在继承泛型类型时,桥方法的合成是为了避免类型变量擦除所带来的的多态灾难。无论我们如何定义一个泛型类型,相应的都会有一个原始类型被自动提供。原始类型的名字就是擦除类型参数的泛型类型的名字。

(3)JVM是如何获取具体类型的呢?答:用反射,也正因为有了反射才促生了泛型。

55. Java程序的执行过程

(1)编译器将Java源代码编译成字节码class文件。

(2)类加载到JVM里面后,执行引擎会把字节码转为可执行代码。

(3)执行的过程,再把可执行代码转为机器码,由底层的操作系统完成执行。

56. 一个.java文件中定义几个类的问题

(1)public权限类最多只能有一个(也可以一个都没有)

(2)这个.java文件名只能是public权限的那个类的类名。如果没有public类,则.java文件的名字是随便的一个类名。

(3)当用javac命令生成编译这个.java文件时,则会针对.java文件中的每一个类生成一个.class文件。 一个源程序文件中定义几个类和接口,则编译该文件就会生成几个以.class为后缀的字节码文件。 

(4)如果类中有内部类,会产生类名$内部类名.class。 如果有匿名类,则会产生类名$1.class。所以类编译不一定会产生1个.class文件而已。

57. 抽象类和接口的区别

(1)抽象类可以有构造方法,接口不不能有构造方法

(2)抽象类中可以有普通成员变量,接口中没有(可有常量)

(3)抽象类中可以包含非抽象普通方法,接口中必须所有方法都是抽象的

(4)抽象类中的抽象方法的访问权限可以是public, protected和默认类型。接口中的抽象方法只能是public, 并且默认即为public abstract的

(5)抽象类中可以包含静态方法,在JDK1.8之前接口中不能包含静态方法,JDK1.8后接口可以。

(6)抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问权限可以是任意的,但接口中定义的变量只能是public static final类型(默认的也是这个)

(7)一个类可以实现多个接口,用逗号隔开,但只能继承一个抽象类。接口不可以实现接口,但是接口可以继承接口,并且一个接口可以继承多个接口,用逗号隔开。

58. Java中的“|” 和“||”

(1)“|”:按位或, 先判断左边条件,不管左边是否可以决定结果,都会执行右边条件

(2)“||”:逻辑或,先判断左边条件,如果左边可以决定结果,那么就不会执行右边条件

59. 三元操作符的转换规则

(1)若两个操作数不可转换,则不做转换,返回值为Object类型。

(2)若两个操作数是明确数据类型的表达式(比如变量),则按照正常的二进制数来转换,int类型转换为long类型,long类型转换为float类型等。

(3)若两个操作数中有一个是数字S, 另外一个是表达式,且其类型标示为T,那么若数字S在T的范围内,则转换为T类型;若S超出了T类型的范围,则T转换为S类型。

(4)若两个操作数都是直接量数字,则返回值类型为范围较大者。

60. 8种基本类型的大小,封装类,默认值,范围等

数组引用变量的默认值是null。

数组变量实例中,如果没有显式的为每个元素赋值,Java就会把该数组的所有元素初始化为元素相应类型的默认值。

61. 什么是对象的序列化

(1)对象的序列化:Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在。即:这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保持(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。

(2)使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的“状态”,即它的成员变量。可见,对象序列化不会关注类的静态变量。

(3)基本数据类型的变量可以直接序列化。

(4)对象要被序列化,它的类必须实现Serializable接口如果一个类中有引用类型的变量,这个引用类型的变量的类也必须实现Serializable接口。如果这个引用类型的变量不想被序列化,则用transient修饰(ObjectInputStream)。

(5)声明为static和transient类型的成员数据不能被序列化,因为static代表类的状态,transient代表对象的临时数据。

62. ThreadLocal类

(1)没有继承Thread类,也没实现Runnable接口。

(2)ThreadLocal类为每一个线程都维护了自己独有的变量拷贝,每个线程都拥有了自己独立的一个变量。所以,ThreadLocal重要作用并不在于多线程间的数据共享,而是数据的独立。

(3)由于每个线程在访问该变量时,读取和修改的,都是自己独有的那一份变量拷贝,不会被其他线程访问。变量被彻底封闭在每个访问的线程中。

(4)ThreadLocal中定义了一个哈希表用于为每个线程都提供一个变量的副本。

63. 关于Servlet的知识点

(1)init()方法:是servlet生命起点,一旦加载了某个servlet,服务器将立即调用它的init()方法。

(2)service()方法:在servlet生命周期中的服务期。用来处理客户机发出的所有请求。默认在HttpServlet类中实现。

根据用户请求的方法,将请求分发到doGet()或是doPost()方法,执行。

doGet()和doPost()是在javax.servlet.http.HttpServlet类中实现的,javax.servlet.http.HttpServle类继承javax.servlet.GenericServlet。

service()方法是在javax.servlet.GenericServlet类中实现的,而javax.servlet.GenericServlet类实现了javax.servlet.Servlet接口。

只有最先定义好service()方法,才可以处理所有的请求。

(3)destroy()方法:标志servlet生命周期的结束。执行destroy()方法后会释放Servlet占用的资源,该方法仅执行一次,即在服务器停止且卸载Servlet时指定。

(4)servlet在多线程下其本身并不是线程安全的。

如果在类中定义成员变量,而在service中根据不同的线程对该成员变量进行更改,那么在并发的时候就会引起错误。最好是,在方法中定义局部变量,而不是类变量或者对象的成员变量。由于方法中的局部变量是在栈中,彼此各自都拥有独立的运行空间而不会互相干扰,因此才做到线程安全。

(5)创建Servlet实例,是由Servlet容器来完成,且创建Servlet实例是在初始化方法init()之前

(6)开发者在开发service方法继承HttpServlet时,如何处理父类的service方法?

一般我们都是不对service方法进行重载(没有特殊需求的话),而只是重载doGet之类的doXxx()方法。减少开发量。即使如果重载service()方法,所有doXxx()都是需要重载的。

注:圆圈表示接口,矩形框表示类

64. Java的异常Exception的常见类型

(1)运行时异常:不需要程序员去处理,当异常出现时,JVM会帮助处理。

ClassCastException        类转换异常

ClassNotFoundException        找不到类异常

IndexOutOfBoundsException        数组越界异常

NullPointerException        空指针异常

ArrayStoreException        数组存储异常,即存储类型不一致

BufferOverflowException        IO操作的异常

(2)非运行时异常:需要程序员手动捕获,或者抛出异常进行显式的处理。因为Java认为Checked异常都是可以被修复的异常。

IOException

SQLException

FileNotFoundException

65. JavaWEB中的多个会话监听类,如HttpSessionListener等

(1)HttpSessionAttributeListener:可以实现此侦听接口,获取此web应用程序中的会话属性列表更改的通知。

(2)HttpSessionBindingListener:当该对象从一个会话中被绑定或者解绑时,通知该对象,这个对象由HttpSessionBindingEvent对象通知。这可能是servlet程序显式地从会话中解绑定属性的结果,可能是由于会话无效,也可能是由于会话超时。

(3)HttpSessionObjectListener:没有该接口。

(4)HttpSessionListener:当web应用程序中的活动会话列表发生更改时,通知该接口的实现类,为了接收该通知事件,必须在web应用程序的部署描述符中配置实现类。

(5)HttpSessionActivationListener:绑定到会话的对象可以监听容器事件,通知他们会话将被钝化,会话将被激活。需要一个在虚拟机之间迁移会话或持久的容器来通知所有绑定到实现该接口会话的属性。

66. 后端向前端传输数据的安全性问题, XSS过滤器

(1)后端获取数据,在向前端输出的过程中,输出前应该采用信息安全部发布的XSSFilter进行相应编码。

(2)XSS过滤器是前端的一种过滤方法。通常,所有的外部输入数据都是不可信的,同时数据库中的数据是敏感的,不能直接对外暴露。

67. Java中的“==”和equals的问题点

(1)Float类和Double类都重写了equals()方法,在比较之前都会判断对象是否同属于Float对象或Double对象,如果不是则直接返回false,如果是再继续比较对应的数值大小。

参考前文第15点:Java语法汇总一(NK)

(2)数组是引用类型,继承Object, 所以数组也有equals()方法,但没有重写,所以比较的是两个数组的地址,相当于"=="。可以使用Arrays.equals()是比较两个数组中的内容,遍历数组中的元素进行一一比较。

68. 复制数组的几种方法和效率高低

复制效率从高到低:

(1)System.arraycopy(): native方法,最快

(2)clone()

(3)Arrays.copyOf():源码中调用System.arraycopy(),多了一个步骤。注意是Arrays。

(4)for()

69. 字母和整数对应的ASCII码值,快速记忆

简单的记忆法:0是48,A是65, a是97

70. subSet() 和 subList()

(1)subSet(from, true, to true):是TreeSet的一个非静态方法,该方法返回从from到to元素的一个set集合,两个boolean类型是确认是否包含边界值用的。

(2)subSet()和subList都是返回原数据结构的一个视图,即返回的集合是原集合的映射,如果原集合有变化,那么返回的集合也会有变化。

71. Off-heap 堆外内存

(1)off-heap:叫做堆外内存。对象存在堆内存中,序列化后在堆外内存。

(2)是JVM进程管理的内存。

(3)将对象从堆中脱离出来序列化,然后存储在一大块内存中,这就像它存储到磁盘一样,但它仍然存在RAM中。?可以理解为对象序列化的字节码文件?

(4)对象在这种状态下不能直接使用,它们必须首先反序列化,也不受垃圾收集器管理,也不属于老年代和新生代。

(5)序列化和反序列化将会影响部分性能,使用堆外内存能够降低GC导致的暂停。

72. HttpServlet容器响应Web客户请求的流程

(1)Web客户向Servlet容器发出http请求。

(2)Servlet容器解析Web客户的Http请求。

(3)Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息。

(4)Servlet容器创建一个HttpResponse对象

(5)Servlet容器调用HttpServlet的service方法,这个方法会根据request的Method来判断具体是指行doGet还是doPost,把HttpRequset和HttpResponse对象作为service方法的参数传给HttpServlet对象。

(6)HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息。

(7)HttpServlet调用HttpResponse的有关方法,生成响应数据。

(8)Servlet容器把HttpServlet的响应结果传给Web客户。

补: doGet或doPost是创建HttpServlet时需要覆盖的方法。

73. 事务隔离级别的相关概念

(1)在数据库中,为了有效保证并发读取数据的正确性,提出了事务隔离级别。

(2)为了解决:更新丢失,脏读,不可重读(包括虚读和幻读)等问题,在标准的SQL规范中,定义了4个事务隔离级别:未授权读取(读未提交);授权读取(读提交);可重复读取;序列化;

(3)Java程序可以设定隔离级别,但是事务隔离级别需要数据库来实现。

74. 抽象类 (abstract) 和 最终类 (final)

(1)抽象类能被继承,最终类不能被继承。

(2)抽象类不能实例化,最终类能实例化。

(3)抽象类中可以没有抽象方法,最终类中可以没有最终方法。

(4)抽象类和最终类,都可以被声明使用。这里说的声明,不是实例化。

最常见的声明方式如下,也就是“向上转型”:

------父亲类型的引用,指向子类的对象;比如 Father son = new Son();

-------接口类型的引用,指向该接口的实现类的对象;

75. Object类的一些常用方法

(1)public final natice Class<?> getClass()

native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。

补充:作用是返回运行时的类的名字。这个运行时的类,通常就是当前类。如果其他类没有重写.getClass()方法,那么通常就是使用的Object类的getClass()方法。比如Date类没有重写getClass方法,那么Date和它的子类的.getClass().getName() 返回的就是当前运行类的名字。


(2)public native int hashCode()

native方法,用于返回对象的哈希码,主要使用在哈希表中,比如jdk中的hashmap
 

(3)public boolean equals(Object obj):

比较两个对象的内存地址是否相等,String类对于该方法进行了重写用户比较字符串的值是否相等
 

(4)protected native Object clone() throws CloneNotSupportedException:

native方法,用于创建并返回当前对象的一份拷贝。

通常,对于任何对象x,表达式x.clone()!=x为true,x.chone().getClass==x.getClass()为true。

Object本身并没有实现cloneable接口,所以不重写clone方法并且进行调用的话,会发生CloneNotSupportedException异常
 

(5)public String toString()

返回类的名字@实例的哈希码的16进制字符串,建议Object所有子类都重写这个方法
 

(6)public final native void notify()

native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)如果有多个线程在等待只会唤醒任意一个
 

(7)public final native void notifyAll()

native方法,并且不能重写。和notify一样,唯一的区别就是会唤醒在此监视器上等待的所有线程,而不只是一个线程
 

(8)public final native void wait(long timeout) throws InterruptedException

native方法,不能重写。暂停线程的执行,注意sleep方法没有释放锁,而wait方法释放了锁。timeout是等待时间
 

(9)public final void wait(long timeout,int nanos) throws InterruptedException :

多了nanos参数,这个参数表示额外时间,以毫秒为单位,范围是0-999999,所以超时时间还需要加上nanos毫秒
 

(10)public final void wait() throws InterruptedException:

跟之前的两个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
 

(11)protected void finalize() throws Throwable:

实例被垃圾回收器回收触发的操作

76. Java内部类

图文参考网络搜索和刷题评论,非原创。

(1)成员内部类

看起来像是外部类的一个成员,所以内部类可以拥有private、public等访问权限修饰;当然,也可以用static来修饰。成员内部类分为:静态内部类和非静态内部类。

1)静态内部类:

使用static修饰的内部类我们称之为静态内部类,我们要知道只要是static修饰的类那它一定是内部类,不可能是外部类。

静态内部类与非静态内部类之间存在一个最大的区别:

非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类的对象,但是静态内部类却没有。没有这个引用就意味着:它的创建是不需要依赖于外围类的对象;它不能使用任何外围类的非static成员变量和方法(因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象)。

注:只有成员内部类才能加static变成静态内部类。静态内部类内允许有static属性、方法;

2)非静态成员内部类

未用static修饰的类。在没有说明是静态成员内部类时,默认成员内部类指的就是非静态成员内部类;

注意:

1)成员内部类访问外部类的信息

成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法

2)创建内部类对象:

成员内部类是依附外部类而存在的,所以要创建成员内部类的对象,前提是必须存在一个外部类的对象。通常有如下两种方法。

OutClass out = new OutClass();

InnerClass inner1 = out.getInner();

InnerClass inner2 = out.new InnerCLass();

3)外部类访问成员内部类信息:

同样,外部类也可以访问内部类的所有成员变量和方法(包括private),但外部类想访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。

4)成员内部类中不能存在任何static的变量和方法:

对于成员内部内并不是完全不能出现static字段的,如果你是使用final和static同时修饰一个属性字段,并且这个字段是基本类型或者String类型的,那么是可以编译通过的。原因:

非静态成员内部类要依赖外部类,所以不能有static变量;
在类加载那一章我们了解到,对于final static的变量是存放在常量池中的,不涉及到类的加载;

 

(2)局部内部类:

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。

局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。

(3)匿名内部类:

匿名内部类是唯一一种没有构造器的类。(??????)

正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。

匿名内部类在编译的时候由系统自动起名为Outer$1.class。

一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。


猜你喜欢

转载自blog.csdn.net/sulia1234567890/article/details/120966791