十、内部类
在一个类内部定义的类,包含内部类的类称为外部类。
内部类的好处:可以直接访问外部类的私有属性和方法,内部类可以把外部类中
相对独立的功能进行封装,内部类需要依赖外部类的对象存在。
缺点:内部类打破类的常规定义(类是由属性和方法组成)
class Outer{
private String name = "Outer";
class Inner{
public void print(){
System.out.println("innner中使用outer的私有属性:"+name);
}
}
}
public class Test30{
public static void main(String[] args){
Outer outer = new Outer();
//在外部实例化内部类对象
Outer.Inner inner = outer.new Inner();
//inner.print();
}
}
内部类在编译后生成的class文件以:外部类$内部类.class 方式命名。
在外部实例化内部类对象使用的语法:
Outer.Inner inner = outer.new Inner();
通常情况下,不建议在类外部直接实例化内部类的对象,为什么?
从封装的思想看,内部类就是一个类中的部分功能的封装,不对外暴露。那如果从
外部去直接实例化内部类,就违反了内部类本身的原则。
那我们应该在外部如何使用内部类的方法呢?
一般情况下,我们会在外部类中定义一个方法来提供给外部访问:
//内部类
class Outer{
private String name = "Outer";
//此方法用于给外部提供访问内部类的方法
public void print(){
Inner inner = new Inner();
inner.print();
}
private class Inner{
public void print(){
System.out.println("innner中使用outer的私有属性:"+name);
}
}
}
在方法中定义一个内部类:
//方法内部类
public void show(){
class Inner2{
public void show(){
System.out.println("show:");
}
}
Inner2 i2 = new Inner2();
i2.show();
}
方法的参数或在方法中声明的变量,在方法内部类中使用时为只读,通常情况下,都把
他们声明为final:
public void show(final int x){
final num = 10;
class Inner2{
public void show(){
System.out.println("show:"+x+num);
}
}
Inner2 i2 = new Inner2();
i2.show();
}
把一个内部类定义在一个方法中,有什么好处?
除了把实现代码集中在一个方法中,使用内部类来隐藏实现细节。(封装)
静态内部类:
定义:
Class outer{
static class StaticInner{
public void print(){
System.out.println(“静态内部类”);
}
}
}
实例化静态内部类:
Outer.StaticInner os = new Outer.StaticInner();
(1)静态内部类,不依赖于外部类对象
(2)不能直接访问外部类的非静态成员变量和方法
(3)静态内部类,就好比是一个外部类,目的是起到封装性,对外部隐藏细节
普通内部类与静态内部类的区别:
内存泄漏:一块内存被占用,无法释放,该内存数据又无法访问到,内存泄漏过多会造成内存溢出。
内存溢出:指的是内存空间不足,无法申请内存空间,此时会报内存溢出异常
由于普通内部类要持有外部类对象,外部类对象就会被该内部类引用,如果此时内部类对象生命周期过长,就会导致外部类对象无法释放,容易导致内存泄漏问题。
匿名内部类:
(1)继承式匿名内部类
abstract class ParemtClass{
pulic abstract void print();
}
Class test{
public static void main(String[] args){
ParentClass pc = new
(3)参数式匿名内部类:
在一个方法调用时,把匿名内部类的实现作为参数传入
Public void print(Eat e,int x){
E.eat();
System.out.println(x);
}
调用该方法:
Class test{
Public static void main(String[] args){
//把一个接口Eat的实现类作为参数传入到print方法中,此写法是不需要在定义一个类去单独实现接口,再实例化后传入方法中,如果实现类的方法执行周期过长,或者逻辑很复杂,是不建议使用的。
Print(new Eat(){
Public void eat(){
System.out.println(“eat”);
}
},10);
//直接调用接口的实现的方法:
New Eat(){
Public void eat(){
System.out.println(“偷懒”);
}
}.eat();
}
}
十一、递归算法
//递归算法必须要有出口,每次递归都会可能产生变量占用内存,所以要注意内存溢出,慎用。
//使用递归算法实现阶乘
//递归:就是方法内部调用自己的方法
//调用的次数越多,越危险
//递归每次会产生临时变量占用内存
//递归唯一的好处就是,在解决类似在文件夹中查找//文件需求时的问题,一般情况下不建议使用
//使用了递归算法实现阶乘
public static int jiecheng2(int num){
if(num==1)return 1;
return num * jiecheng2(num-1);
}
//没有使用递归算法实现阶乘
public static int jiecheng1(int num){
int arithmetic = num;
int i = num-1;
do{
arithmetic = arithmetic * i;
i--;