内部类——成员内部类
- 把一个类定义在另一个类的内部称为内部类
- 内部类可以轻松访问外部类的私有属性
- 外部类不能访问内部类的私有属性
一个java文件可以包含n个class,但最终只有一个public类
如果多个class在文件里面是并列的关系,则外部文件展示也是多个class文件。但如果是包含的形式则不会显式多个文件
public class Runner{
private int age;
class RunnerIn{
private int sentiment;
System.out.println(age)//内部类访问外部类属性
}
}
public static void main(String[] args){
Runner.RunnerIn runner = new Runner().new RunnerIn();
}
使用:
创建内部类的时候,跟之前的方法不一样,需要在内部类的前面添加外部类进行修饰
外部类访问内部类的方法:
public class Runner{
private int age;
RunnerIn in = new RunnerIn();
System.out.println(in.sentiment);//外部类访问内部类属性
class RunnerIn{
private int sentiment;
}
}
特点:
内部类可以当作是类中的一个普通成员变量,只不过此成员变量是class类型
- 内部类可以方便地访问外部类的私有属性
- 外部类不能访问内部类的私有属性,但是如果创建了内部类的对象,此时可以在外部类中访问内部类的私有属性
- 内部类不能定义静态属性
注意事项:
(1)外部类不能直接使用内部类的成员和方法
(2)如果外部类和内部类具有相同的成员变量和方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,需要使用 外部类名.this.属性名 来访问
public class Outer{
private String name = "zhangsan";
class Inter{
private String name = "lisi";
public void show(){
System.out.pringln(name);//优先访问内部类属性
System.out.println(this.name);//访问内部类属性
System.out.println(Outer.this.name);//访问外部类属性
}
}
}
语法:
- 外部类 外部类对象 = new 外部类();
- 外部类.内部类 内部类对象 = 外部类对象.new 内部类();
public static voiod main(String[] args){
Outer out = new Outer();//创建外部类对象
Outer.Inner inner = Out.new Inner();//创建内部类的对象
inner.print();//访问内部类的方法
}
分类:
- 匿名内部类(常用):当定义了一个类,实现了某个接口的时候,在使用过程中只需要使用一次,没有其他用途。考虑到代码编写的简洁,可以考虑不创建具体的类,而采用new interface(){添加未实现的方法} 这种方式就叫做匿名内部类
class Outer{
Thread thread = new Thread(new Runnerble(){
//内部方法实现
})
}
- 静态内部类:在内部类中可以定义静态内部类,使用static关键字进行修饰,使用规则:
外部类.内部类 类的引用名称 = new 外部类.内部类();
public class Outer{
static class Inner{
}
}
public static void main(String[] args){
Outer.Inner outer = new Outer.Inner();
}
- 方法内部类(用的较少):
方法内部类是指将内部类定义在外部类的方法中。
注意事项:
1、方法内部类不能在外部类的方法以外的地方使用,所以,方法内部类不能使用访问控制符和static修饰符。
2、方法内部类不能使用访问控制符和static修饰符
3、使用的时候需要注意,只能在方法中创建对象,因为此class 的作用域就是当前方法
public class MethodInnerClass{
publid void show(){
System.out.println("show");
class InnerClass{
private String name;
public void test(){
Systrm.out.pringln("test");
}
}
}
}
垃圾回收机制
- 对象空间的分配:
-使用new关键字创建对象即可 - 对象空间的释放:
-传统的C/C++语言,需要程序员负责回收已经分配的内存。显式回收垃圾回收的缺点:
程序忘记及时回收,从而导致内存泄漏,降低系统性能。
程序错误回收程序核心类库的内存,导致系统崩溃
-java语言不需要程序员直接控制内存回收,是由JRE在后台自动回收不再使用的内存,称为垃圾回收机制(Garbage Collection)
可以提高编程效率
保护程序的完整性
其开销影响性能。java虚拟机必须跟踪程序中有用的对象,确定哪些是无用的
垃圾回收机制的关键点
- 垃圾回收机制只回收JVM堆内存里的对象空间
- 对其他物理连接,比如数据库连接、输入流输出流、socket连接无能为力
- 现在的JVM有多种垃圾回收实现算法,表现各异
- 垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行
- 可以将对象的引用变量设置为null,暗示垃圾回收机制可以回收该对象。
- 程序员可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有一些效果,但是系统是进行垃圾回收依然不确定。
- 垃圾回收机制回收任何对象之前,总会先调用它的finalize方法(如果覆盖该方法,让一个新的引用变量重新引用该对象,则会重新激活对象)
- 永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用
异常
在程序运行过程中,出现的不正常情况叫做异常
注意:
- 相同的代码在运行的时候,根据输入的参数或者操作的不同,有可能会发生异常,也有可能不会发生异常,应该在写代码的过程中尽可能的保证代码的正确性,不要导出都是bug
- 如果要解决代码中出现的异常,需要添加非常复杂的代码逻辑进行判断,会使代码变得非常臃肿,不利于维护,代码可读性比较差。因此,推荐大家使用异常机制来处理程序运行过程中出现的问题
- 程序在运行过程中如果出现了问题,会导致后面的代码无法正常执行,而使用异常机制之后,可以对异常进行处理,同时后续的代码会继续执行,不会中断整个程序
- 在异常的处理过程中,不要只是简单的输出错误,要尽可能的将详细的异常信息进行输出
e.printStackTrace();打印异常的堆栈信息。可以从异常信息的最后一行开始追踪,寻找自己编写的java类
异常处理方式
-
捕获异常
1、try{代码逻辑}catch(Exception e){异常处理逻辑}
2、try{代码逻辑}catch(具体的异常Exception e){异常处理逻辑}//catch具体的异常:可以针对每一种具体的异常做相应的更丰富的处理(推荐)
注意:当使用多重的catch的时候一定要注意相关异常的顺序,将子类放在最前面的catch,父类放在后面的catch -
执行过程中可能存在的情况
1、正常执行,只执行try中的代码
2、遇到异常情况,会处理try中异常代码之前的逻辑,后面的逻辑不会执行,最后会执行catch中的代码
3、使用多重catch的时候,会遇到异常子类不匹配的情况,此时依然会报错,因此建议在catch的最后将所有的异常的父类写上
System.err.println(“错误提示”)
调用方法输出异常信息
方法名 | 说明 |
---|---|
void printStackTrace() | 输出异常的堆栈信息 |
– | – |
String getMessage | 返回异常信息描述字符串,是pringStackTrace()输出信息的一部分 |
常见异常类型
异常类型 | 说明 |
---|---|
Exception | 异常层次结构的父亲 |
ArithmeticException | 算术错误情形,如以0作为除数 |
ArrayIndexOutOfBoundsException | 数组下标越界 |
NullPointerException | 尝试访问null对象成员 |
ClassNotFoundException | 不能加载所需的类 |
IllegaArgumentException | 方法接收到非法参数 |
ClassCastException | 对象强制类型转换出错 |
NumberFormatException | 数字格式转换异常,如把“abc”转换成数字 |
public static void main(String[] args){
try{
//运行程序逻辑
}catch(ArrayIndexOutOfBoundsException e){
System.err.pringln("数组长度不足!")
e.printStackTrace()
}catch(Exception e){
e.printStackTrace()
}
System.out.println("程序使用结束!")
}