上图描述了三个字符串拼接成一个新的字符串的内存使用情况,可以看到栈中text1指向的地址被改变,但是堆中产生两个没有指向的对象垃圾,这是非常耗费内存的,所以平常应该避免字符串拼接。
PC寄存器PC寄存器保存的是当前正在执行的 JVM指令的 地址 ;
在Java程序中, 每个线程启动时, 都会创建一个PC寄存器 ;
本地方法栈保存本地(native)方法的地址
内部类在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
广泛意义上的内部类一般来说包括这四种:
1、成员内部类
2、局部内部类
3、匿名内部类
4、静态内部类
成员内部类成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:
public class Demo{ public static void main(String[] args){ //外部使用成员内部类 Outer outter = new Outer(100); Outer.Inner inner = outter.new Inner(); inner.say(); //输出:200 // 100 } } class Outer { private double x = 0; public Outer(double x) { this.x = x; } class Inner { private double x=200; //内部类 public void say() { System.out.println(x); System.out.println(Outer.this.x); } } }特点: 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。 不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。
如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
局部内部类局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
例如:
interface Person{ public void say(); } public class Demo{ public static void main(String[] args){ //局部内部类 class PersonImp implements Person{ @Override public void say(){ System.out.prinln("新编写的局部内部类的say方法内容"); } } PersonImp p=new PersonImp(); //这里像调用haha()方法,但是需要一个Person类,为此专门创建一个class文件类很浪费时间,所以使用局部内部类 haha(p); } public static void haha(Person p){ } } //窗口关闭 public static void main(String[] args){ Frame f=new Frame("QQ登陆器"); f.setVisible(true); f.setSize(300,200); class MyWindowListener implements WindowListener{ @Override public void windowClosing(WindowEvent e){ System.out.println("哈哈哈"); } } MyWindowListener l=new MyWindowListener(); //想要添加一个窗口关闭的事件,可以使用局部类 f.addWindowListener(l); }注意:局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。局部内部类也是只能访问final类型变量。
匿名内部类匿名内部类由于没有名字,所以它的创建方式有点儿奇怪。匿名内部类创建出来只能使用一次,和匿名对象类似。创建格式如下:
new 父类构造器(参数列表)|实现接口() { //匿名内部类的类体部分 } interface Person{ public void say(); } public class Demo{ public static void main(String[] args){ //匿名内部类 Person p=new Person(){ public void say(){ System.out.println("锄禾日当午"); } } haha(p); } public static void haha(Person p){ } }在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐式的。
在使用匿名内部类的过程中,我们需要注意如下几点:
1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或 者实现一个接口。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
6、只能访问final型的局部变量。JDK1.8之后变量默认为final类型,但是只要第二次赋值,就不再是final类型的了。
只能访问final类型的局部变量的原因,因为局部类编译的时候是单独编译成一个文件,所以在文件中有final变量的备份。
静态内部类静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。
静态内部类是不需要依赖于外部类对象的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法。