首页 > 系统相关 >Java虚拟机(JVM)内存底层分析

Java虚拟机(JVM)内存底层分析

时间:2023-07-04 20:11:34浏览次数:47  
标签:Java String 对象 虚拟机 接口 JVM 字符串 父类 方法

对象和类的详解

类:我们叫做class。 对象:我们叫做Object,instance(实例)。

总结

1.类可以看成一类对象的模板,对象可以看成该类的一个具体实例。

2.类是用于描述同一类型的对象的一个抽象概念,类中定义了这一类对象所应具有的共同的属性、方法。

类的定义:对于一个类来说,有三种成员:属性field、方法method、构造器constructor。

属性(field 成员变量)

1.属性用于定义该类或该类对象包含的数据或者说静态特征。属性作用范围是整个类体。

2.在定义成员变量时可以对其初始化,如果不对其初始化,Java使用默认的值对其初始化。

属性定义格式:[修饰符] 属性类型 属性名 = [默认值] ;

构造方法(构造器 constructor)

构造器用于对象的初始化,而不是创建对象!

声明格式:[修饰符] 类名(形参列表){ //n条语句}

构造器4个要点:

1.构造器通过new关键字调用!!

2.构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造器里使用return返回某个值。

3.如果我们没有定义构造器,则编译器会自动定义一个无参的构造方法。如果已定义则编译器不会自动添加!

4.构造器的方法名必须和类名一致!

构造方法的重载

构造方法也是方法。与普通方法一样,构造方法也可以重载。

JAVA虚拟机内存模型概念

Java虚拟机的内存可以分为三个区域:栈stack、堆heap、方法区method area。

虚拟机栈(简称:栈)的特点如下:

1.栈描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)

2.JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)

3.栈属于线程私有,不能实现线程间的共享!

4.栈的存储特性是“先进后出,后进先出”

5.栈是由系统自动分配,速度快!栈是一个连续的内存空间!

堆的特点如下:

1.堆用于存储创建好的对象和数组(数组也是对象)

2.JVM只有一个堆,被所有线程共享

3.堆是一个不连续的内存空间,分配灵活,速度慢!

4.堆被所有的线程所共享,在堆上的区域,会被垃圾回收器做进一步划分,例如新生代、老年代的划分。

方法区(也是堆)特点如下:

1.方法区是JAVA虚拟机规范,可以有不同的实现。

i. JDK7以前是“永久代”

ii. JDK7部分去除“永久代”,静态变量、字符串常量池都挪到了堆内存中

iii. JDK8是“元数据空间”和堆结合起来。

2.JVM只有一个方法区,被所有线程共享!

3.方法区实际也是堆,只是用于存储类、常量相关的信息!

4.用来存放程序中永远是不变或唯一的内容。(类信息【Class对象,反射机制中会重点讲授】、静态变量、字符串常量等)

5.常量池主要存放常量:如文本字符串、final常量值。

参数传值机制

Java中,方法中所有参数都是“值传递”,也就是“传递的是值的副本”。 也就是说,我们得到的是“原参数的复印件,而不是原件”。

1.基本数据类型参数的传值:传递的是值的副本。 副本改变不会影响原件。

2. 引用类型参数的传值:传递的是值的副本。但是引用类型指的是“对象的地址”。

因此,副本和原参数都指向了同一个“地址”,改变“副本指向地址对象的值,也意味着原参数指向对象的值也发生了改变”。

垃圾回收机制(Garbage Collection)

垃圾回收原理和算法

内存管理

Java的内存管理很大程度就是:堆中对象的管理,其中包括对象空间的分配和释放。

1.对象空间的分配:使用new关键字创建对象即可

2.对象空间的释放:将对象赋值null即可。

垃圾回收过程

任何一种垃圾回收算法一般要做两件基本事情:

1.发现无用的对象

2.回收无用对象占用的内存空间。

垃圾回收机制保证可以将“无用的对象”进行回收。

无用的对象指的就是没有任何变量引用该对象。Java的垃圾回收器通过相关算法发现无用对象,并进行清除和整理。

垃圾回收相关算法

1.引用计数法

堆中的每个对象都对应一个引用计数器,当有引用指向这个对象时,引用计数器加1,而当指向该对象的引用失效时(引用变为null),引用计数器减1,最后如果该对象的引用计算器的值为0时,则Java垃圾回收器会认为该对象是无用对象并对其进行回收。

优点是算法简单,缺点是“循环引用的无用对象”无法别识别。

2.引用可达法(根搜索算法)

程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。

通用的分代垃圾回收机制

分代垃圾回收机制,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。

我们将对象分为三种状态:年轻代、年老代、永久代。同时,将处于不同状态的对象放到堆中不同的区域。

1. 年轻代

所有新生成的对象首先都是放在Eden区。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象,对应的是Minor GC,每次 Minor GC 会清理年轻代的内存,算法采用效率较高的复制算法,频繁的操作,但是会浪费内存空间。当“年轻代”区域存放满对象后,就将对象存放到年老代区域。

2. 年老代

在年轻代中经历了N(默认15)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。年老代对象越来越多,我们就需要启动Major GC和Full GC(全量回收),来一次大扫除,全面清理年轻代区域和年老代区域。

3. 永久代

用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响。JDK7以前就是“方法区”的一种实现。JDK8以后已经没有“永久代”了,使用metaspace元数据空间和堆替代。

Minor GC:

用于清理年轻代区域。Eden区满了就会触发一次Minor GC。清理无用对象,将有用对象复制到“Survivor1”、“Survivor2”区中。

Major GC:

用于清理年老代区域。

Full GC:

用于清理年轻代、年老代区域。 成本较高,会对系统性能产生影响。

JVM调优和Full GC

在对JVM调优的过程中,很大一部分工作就是对于Full GC的调节。有如下原因可能导致Full GC:

1.年老代(Tenured)被写满

2.永久代(Perm)被写满

3.System.gc()被显式调用

4.上一次GC之后Heap的各域分配策略动态变化

内存泄漏:指堆内存由于某种原因程序未释放,造成内存浪费,导致运行速度减慢甚至系统崩溃等。

开发中容易造成内存泄露的操作:

1.创建大量无用对象

比如:大量拼接字符串时,使用了String而不是StringBuilder。

2. 静态集合类的使用

像HashMap、Vector、List等的使用最容易出现内存泄露,这些静态变量的生命周期 和应用程序一致,所有的对象也不能被释放。

3. 各种连接对象(IO流对象、数据库连接对象、网络连接对象)未关闭

IO流对象、数据库连接对象、网络连接对象等连接对象属于物理连接,和硬盘或者网 络连接,不使用的时候一定要关闭。

4. 监听器的使用不当

释放对象时,没有删除相应的监听器

其他要点

  1. 程序员无权调用垃圾回收器。

2.程序员可以调用System.gc(),该方法只是通知JVM,并不是运行垃圾回收器。尽量少用,会申请启动Full GC,成本高,影响系统性能。

3.Object对象的finalize方法,是Java提供给程序员用来释放对象或资源的方法,但是尽量少用。

this关键字

this的用法:

1.普通方法中,this总是指向调用该方法的对象。

2.构造方法中,this总是指向正要初始化的对象。

this的其他要点:

1.this()调用重载的构造方法,避免相同的初始化代码。但只能在构造方法中用,并且必须位于构造方法的第一句。

2.this不能用于static方法中。

3.this是作为普通方法的“隐式参数”,由系统传入到方法中。

static 关键字

静态变量(类变量)、静态方法(类方法):static声明的属性或方法。

静态变量/静态方法生命周期和类相同,在整个程序执行期间都有效。它有如下特点:

1.为该类的公用变量,属于类,被该类的所有实例共享,在类载入时被初始化。

2.static变量只有一份。

3.一般用“类名.类变量/方法”来调用。

4.在static方法中不可直接访问非static的成员

静态初始化块

1.构造方法用于对象的普通属性初始化。

2.静态初始化块,用于类的初始化操作,初始化静态属性。

3.在静态初始化块中不能直接访问非static成员。

变量的分类和作用域

变量有三种类型:局部变量、成员变量(也称为实例变量)和静态变量。

类型 声明位置 从属于 生命周期(作用域)

局部变量 方法或语句块内部 方法/语句块 从声明处开始,到方法或语句块 结束

成员变量(实例变量) 类内部,方法外部 对象 对象创建,成员变量也跟着创建。 对象消失,成员变量也跟着消失;

静态变量(类变量) 类内部,static修饰 类 类被加载,静态变量就有效;

包机制(package、import)

包(package)相当于文件夹对于文件的作用。用于管理类、用于解决类的重名问题。

package的使用有两个要点:

1.通常是类的第一句非注释性语句。

2.包名:域名倒着写即可,便于内部管理类。

注意事项

1.写项目时都要加包,不要使用默认包。

2.com.gao和com.gao.car,这是两个完全独立的包。只是逻辑上看,后者是前者的一部分。

在IDEA项目中新建包

1.在src目录上单击右键,选择new->package

2.在package窗口上输入包名即可

3.即可在src下面看到包

4.接下来,我们就可以在包上单击右键,新建类

JDK中的主要包

Java中的常用包 说明

java.lang 包含一些Java语言的核心类,如String、Math、Integer、System和Thread。

java.awt 包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。

java.net 包含执行与网络相关的操作的类。

java.io 包含能提供多种输入/输出功能的类。

java.util 包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数。

导入类import

如果要使用其他包的类,需使用import,从而在本类中直接通过类名来调用,否则就需要书写类的完整包名和类名。

注意要点

1.Java会默认导入java.lang包下所有的类,因此这些类我们可以直接使用。

2.如果导入两个同名的类,只能用包名+类名来显示调用相关类:java.util.Date date = new java.util.Date();

静态导入(static import): 其作用是用于导入指定类的静态属性和静态方法,这样我们可以直接使用静态属性和静态方法。

面向对象三大特征:继承、封装、多态

继承有两个主要作用:

1.代码复用,更加容易实现类的扩展

2.方便建模

instanceof 运算符

instanceof是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则,返回false。

继承使用要点

1.父类也称作超类、基类。 子类:派生类等。

2.Java中只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。

3.Java中类没有多继承,接口有多继承。

4.子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法),但不见得可以直接访问(比如,父类私有的属性和方法)。

5.如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object。

方法重写override:子类重写父类的方法,可以用自身行为替换父类行为。重写是实现多态的必要条件。

方法重写需要符合下面的三个要点:

1.= =:方法名、形参列表相同。

2.≤:返回值类型和声明异常类型,子类小于等于父类。

3.≥:访问权限,子类大于等于父类。

final关键字

final关键字的作用:

1.修饰变量: 被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。

final int MAX_SPEED = 120;

2.修饰方法:该方法不可被子类重写。但是可以被重载!

final void study(){}

3.修饰类: 修饰的类不能被继承。比如:Math、String等。

final class A {}

 

继承和组合

 

除了继承,“组合”也能实现代码的复用!“组合”核心是“将父类对象作为子类的属性”。

 

组合比较灵活。继承只能有一个父类,但是组合可以有多个属性。所以,有人声称“组合优于继承,开发中可以不用继承”,但是,不建议大家走极端。

 

Object类详解:所有类都是Object类的子类,也都具备Object类的所有特性。

 

Object类基本特性

 

1.Object类是所有类的父类,所有的Java对象都拥有Object类的属性和方法。

 

2.如果在类的声明中未使用extends,则默认继承Object类。

 

Object类

 

public class Person {

 

    ...

 

}

 

//等价于:

 

public class Person extends Object {

 

    ...

 

}

 

toString方法

 

Object类中定义有public String toString()方法,其返回值是 String 类型。

 

Object类中toString方法的源码为:

 

public String toString() {

 

    return getClass().getName() + "@" + Integer.toHexString(hashCode());

 

}

 

根据如上源码得知,默认会返回“类名+@+16进制的hashcode”。在打印输出或者用字符串连接对象时,会自动调用该对象的toString()方法。

 

IDEA快捷键和相关操作:

 

1.类的结构视图:alt+7

 

2.看类的源码:ctrl+左键

 

3.自动生成构造器、get、set方法、equals等:alt+insert

 

4.查看错误:alt+enter

 

快捷输出常见字符串:

 

a) main public static void main(String[] args){}

 

b) sout System.out.println();

 

c) soutm System.out.println(“描述:所在类中的,所在方法”);

 

==和equals方法

 

1.==代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。

 

2.equals()提供定义“对象内容相等”的逻辑。比如,我们在公安系统中认为id相同的人就是同一个人、学籍系统中认为学号相同的人就是同一个人。

 

3.equals()默认是比较两个对象的hashcode。但,可以根据自己的要求重写equals方法。

 

super关键字

 

1.super“可以看做”是直接父类对象的引用。可通过super来访问父类中被子类覆盖的方法或属性。

 

2.使用super调用普通方法,语句没有位置限制,可以在子类中随便调用。

 

3.在一个类中,若是构造方法的第一行没有调用super(...)或者this(...); 那么Java默认都会调用super(),含义是调用父类的无参数构造方法。

 

继承树追溯

 

属性/方法查找顺序:(比如:查找变量h)

 

1.查找当前类中有没有属性h

 

2.依次上溯每个父类,查看每个父类中是否有h,直到Object

 

3.如果没找到,则出现编译错误。

 

4.上面步骤,只要找到h变量,则这个过程终止。

 

构造方法调用顺序:

 

1.构造方法第一句总是:super(…)来调用父类对应的构造方法。所以,流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。

 

注:静态初始化块调用顺序,与构造方法调用顺序一样,不再重复。

 

封装(encapsulation)封装是面向对象三大特征之一。

 

封装的作用和含义

 

我们程序设计要追求“高内聚,低耦合”。

 

高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合是仅暴露少量的方法给外部使用,尽量方便外部调用。

 

编程中封装的具体优点:

 

1.提高代码的安全性。

 

2.提高代码的复用性。

 

3.“高内聚”:封装细节,便于修改内部代码,提高可维护性。

 

4.“低耦合”:简化外部调用,便于调用者使用,便于扩展和协作

 

封装的实现—使用访问控制符

 

1.Java是使用访问控制符来控制哪些细节需要封装,哪些细节需要暴露的。

 

2.Java中4种访问控制符分别为private、default、protected、public。

 

【注】关于protected的两个细节:

 

1.若父类和子类在同一个包中,子类可访问父类的protected成员,也可访问父类对象的protected成员。

 

2.若子类和父类不在同一个包中,子类可访问父类的protected成员,不能访问父类对象的protected成员。

 

开发中封装的简单规则:

 

1.属性一般使用private访问权限。

 

2.属性私有后, 提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(注意:boolean变量的get方法是is开头!)。

 

3.方法:一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。

 

多态(polymorphism)多态指的是同一个方法调用,由于对象不同可能会有不同的行为。

 

多态的要点:

 

1.多态是方法的多态,不是属性的多态(多态与属性无关)。

 

2.多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。

 

3.父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。

 

对象的转型(casting)

 

父类引用指向子类对象,我们称这个过程为向上转型,属于自动类型转换。

 

向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法。

 

这时,我们就需要进行类型的强制转换,我们称之为向下转型。

 

抽象方法和抽象类

 

抽象方法

 

1.使用abstract修饰的方法,没有方法体,只有声明。

 

2。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。

 

抽象类

 

1.包含抽象方法的类就是抽象类。

 

2.通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。

 

抽象类的使用要点:

 

1.有抽象方法的类只能定义成抽象类

 

2.抽象类不能实例化,即不能用new来实例化抽象类。

 

3.抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用。

 

4.抽象类只能用来被继承。

 

5.抽象方法必须被子类实现。

 

接口interface

 

接口就是一组规范(就像我们人间的法律一样),所有实现类都要遵守。

 

为什么需要接口?接口和抽象类的区别?

 

1.接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全面地专业地实现了:规范和具体实现的分离。

 

2.接口是两个模块之间通信的标准,通信的规范。如果能把你要设计的模块之间的接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。

 

接口和实现类不是父子关系,是实现规则的关系。

 

比如:我定义一个接口Runnable,Car实现它就能在地上跑,Train实现它也能在地上跑,飞机实现它也能在地上跑。

 

就是说,如果它是交通工具,就一定能跑,但是一定要实现Runnable接口。

 

声明格式:

 

[访问修饰符] interface 接口名  [extends 父接口1,父接口2…]  {

 

常量定义;   

 

方法定义;

 

}

 

定义接口的详细说明:

 

1.访问修饰符:只能是public或默认。

 

2.接口名:和类名采用相同命名机制。

 

3.extends:接口可以多继承。

 

4.常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。

 

5.方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。

 

要点

 

1.子类通过implements来实现接口中的规范。

 

2.接口不能创建实例,但是可用于声明引用变量类型。

 

3.一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的。

 

4.JDK1.8(不含8)之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。

 

5.JDK1.8(含8)后,接口中可以包含普通的静态方法、默认方法。

 

接口中定义静态方法和默认方法(JDK8)

 

JAVA8之前,接口里的方法要求全部是抽象方法。

 

JAVA8(含8)之后,以后允许在接口里定义默认方法和静态方法。

 

Java 8及以上新版本,允许给接口添加一个非抽象的方法实现,只需要使用 default 关键字即可,这个特征又叫做默认方法(也称为扩展方法)。

 

默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。

 

作为替代方式,接口可以提供默认方法的实现,所有这个接口的实现类都可以得到默认方法。

 

JDK8新特性_静态方法

 

JAVA8以后,我们也可以在接口中直接定义静态方法的实现。这个静态方法直接从属于接口(接口也是类,一种特殊的类),可以通过接口名调用。

 

如果子类中定义了相同名字的静态方法,那就是完全不同的方法了,直接从属于子类。可以通过子类名直接调用。

 

接口的多继承

 

接口支持多继承。和类的继承类似,子接口extends父接口,会获得父接口中的一切。

 

interface A {

 

    void testa();

 

}

 

interface B {

 

    void testb();

 

}

 

/**接口可以多继承:接口C继承接口A和B*/

 

interface C extends A, B {

 

    void testc();

 

}

 

public class Test implements C {

 

    public void testc() {

 

}

 

    public void testa() {

 

    }

 

    public void testb() {

 

    }

 

}

 

字符串String类详解

 

String是最常用的类,要掌握String类常见的方法,它底层实现也需要掌握好,不然在工作开发中很容易犯错。

 

1.String类又称作不可变字符序列。

 

2.String位于java.lang包中,Java程序默认导入java.lang包下的所有类。

 

3.Java字符串就是Unicode字符序列,例如字符串“Java”就是4个Unicode字符’J’、’a’、’v’、’a’组成的。

 

4.Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义的类String,每个用双引号括起来的字符串都是String类的一个实例。

 

String类和常量池

 

常量池分了以下三种:

 

1. 全局字符串常量池

 

2. class文件常量池

 

3. 运行时常量池(Runtime Constant Pool)

 

String类的常用方法列表

 

方法                   解释说明

 

char charAt(int index)            返回字符串中第index个字符

 

boolean equals(String other)         如果字符串与other相等,返回true;否 则,返回false。

 

boolean equalsIgnoreCase(String other)     如果字符串与other相等(忽略大小写),则 返回true;否则,返回false。

 

int indexOf(String str)            返回从头开始查找第一个子字符串str在字符 串中的索引位置。如果未找到子字符串str, 则返回-1。

 

lastIndexOf()                返回从末尾开始查找第一个子字符串str在字 符串中的索引位置。如果未找到子字符串str, 则返回-1。

 

int length()                 返回字符串的长度。

 

String replace(char oldChar,char newChar)     返回一个新串,它是通过用 newChar 替换此 字符串中出现的所有oldChar而生成的。

 

boolean startsWith(String prefix)         如果字符串以prefix开始,则返回true。

 

boolean endsWith(String prefix)         如果字符串以prefix结尾,则返回true。

 

String substring(int beginIndex)         返回一个新字符串,该串包含从原始字符串 beginIndex到串尾。

 

String substring(int beginIndex,int endIndex)   返回一个新字符串,该串包含从原始字符串 beginIndex到串尾或endIndex-1的所有字符。

 

String toLowerCase()            返回一个新字符串,该串将原始字符串中的所 有大写字母改成小写字母。

 

String toUpperCase()             返回一个新字符串,该串将原始字符串中的所 有小写字母改成大写字母。

 

String trim()                 返回一个新字符串,该串删除了原始字符串头 部和尾部的空格。

 

字符串相等的判断

 

1.equals方法用来检测两个字符串内容是否相等。如果字符串s和t内容相等,则s.equals(t)返回true,否则返回false。

 

2.要测试两个字符串除了大小写区别外是否是相等的,需要使用equalsIgnoreCase方法。

 

3.判断字符串是否相等不要使用==。

 

内部类

 

我们把一个类放在另一个类的内部定义,称为内部类(inner class)。

 

内部类的两个要点:

 

1.内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。

 

2.内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。但外部类不能访问内部类的内部属性。

 

注意:

 

内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类。编译完成后会出现Outer.class和Outer$Inner.class两个类的字节码文件。

 

所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。

 

非静态内部类

 

1.非静态内部类对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。

 

2.非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。

 

3.非静态内部类不能有静态方法、静态属性和静态初始化块。

 

4.成员变量访问要点:

 

(1)内部类属性:this.变量名。

 

(2)外部类属性:外部类名.this.变量名。

 

内部类的访问:

 

\1. 外部类中定义内部类:new Inner()。

 

\2. 外部类以外的地方使用非静态内部类:Outer.Inner varname = new Outer().new Inner()。

 

静态内部类定义方式:

 

static class  ClassName {

 

//类体

 

}

 

使用要点:

 

1.静态内部类可以访问外部类的静态成员,不能访问外部类的普通成员。

 

2.静态内部类看做外部类的一个静态成员。

 

匿名内部类:适合那种只需要使用一次的类。比如:键盘监听操作等等。在安卓开发、awt、swing开发中常见。

 

语法:

 

new 父类构造器(实参类表) \实现接口 () {

 

          //匿名内部类类体!

 

}

 

注意

 

1.匿名内部类没有访问修饰符。

 

2.匿名内部类没有构造方法。因为它连名字都没有那又何来构造方法呢。

 

局部内部类

 

1.定义在方法内部的,作用域只限于本方法,称为局部内部类。

 

2.局部内部类在实际开发中应用很少。

 

标签:Java,String,对象,虚拟机,接口,JVM,字符串,父类,方法
From: https://www.cnblogs.com/shidawuyu/p/17526884.html

相关文章

  • java的vscode自动补全
    1.vscode补全打印、循环和main函数vscode支持Eclipse和IDEA两个IDE的代码补全方式具体如下表: 代码片段Eclipse风格快捷方式IDEA风格快捷方式System.out.println()sysoutsoutSystem.err.println()syserrserr当前函数签名的System.out.println()sys......
  • 一些Java编程中的基本概念
    介绍一些编程中的基本概念,比如:标识符、变量、常量、数据类型、运算符、基本数据类型的类型转换等。二进制和十进制的转化1.十进制整数转换为二进制整数采用"除2取余,逆序排列"法。2.二进制转十进制采用“权相加法”。注释在Java中根据注释的功能不同,主要分为单行注释、多行注......
  • java调用filter,map方法
    java的集合类,没有直接实现filter,map这些函数式方法,要调用这些方法,可以使用Java8的StreamAPI详细使用可参考:Java8中Stream详细用法大全 Java8的StreamAPI的坑1.没有直接的findObj方法findFirst和findAny都不支持传入条件要从list中查找一个对象,只能通过filte......
  • Java编程里的控制语句
    控制语句:把语句组合成能完成一定功能的小逻辑模块。它分为三类:顺序、选择和循环。1.“顺序结构”代表“先执行a,再执行b”的逻辑。2.“条件判断结构”代表“如果…,则…”的逻辑。3.“循环结构”代表“如果…,则重复执行…”的逻辑。条件判断结构(选择结构)条件判断结构有:if结构......
  • PAT乙级【Java题解合集】
    ✨说在前面       这个暑假博主用大概两周不到的闲暇时间把PAT乙级的110道算法题全部肝完了,个人感觉题目的难度大部分在中等偏下,大概有二十道左右的题目还是蛮有意思的,值得细细去钻研,本专栏非常适合新手入门算法,也适合Java算法老手巩固一些基本知识点,由于C站上关于PAT乙级J......
  • 简单了解java
    Java各版本的含义JavaSE(JavaStandardEdition):标准版,定位在个人计算机上的应用JavaEE(JavaEnterpriseEdition):企业版,定位在服务器端的应用JavaME(JavaMicroEdition):微型版,定位在消费性电子产品的应用上Java的特性和优势1.跨平台/可移植性:这是Java的核心优势。2.安全性3.面......
  • 常用的前端JavaScript方法封装
     1、输入一个值,返回其数据类型**functiontype(para){returnObject.prototype.toString.call(para)} 2、数组去重functionunique1(arr){return[...newSet(arr)]}functionunique2(arr){varobj={};returnarr.filter(ele=>{if......
  • 【10.0】前端基础之JavaScript进阶
    【10.0】前端基础之JavaScript进阶【一】自定义对象可以看成Python中的字典,但是在JS中的自定义对象要比Python里面的字典操作起来更方便【1】创建自定义对象方式一vard={"键":"值",};操作方法vardict={"name":"dream","age":18};vardict={"name":"dream&......
  • java http大文件断点续传上传示例
    ​ 4GB以上超大文件上传和断点续传服务器的实现随着视频网站和大数据应用的普及,特别是高清视频和4K视频应用的到来,超大文件上传已经成为了日常的基础应用需求。但是在很多情况下,平台运营方并没有大文件上传和断点续传的开发经验,往往在网上找一些简单的PHP或者Java程序来实现基......
  • java开发环境的搭建
    卸载JDK1、删除java的安装目录2、删除JAVA_HOME3、删除path下关于java的目录4、打开命令提示符,输入java-version检查jdk是否卸载成功 安装JDK1、百度搜索jdk8,找到下载地址2、下载电脑对应的版本3、双击安装JDK4、记住安装的路径5、配置环境变量:1)我的电脑→右键......