Java从入门到精通 第11章 类的高级特性

目录

Java类包

final变量

final方法

final类

内部类


Java类包

  • 使用package 定义包名,通常使用Internet域名的反序作为包名
  • 使用import导入包,导入包中所有类import com.lzw.*; 但并不会指定这个包的子包的所有类。 或者导入指定类import com.lzw.Math;
  • 同一个包中的类可以不放在同一个位置,只要在CLASSPATH中指定了路径
  • 使用import static导入静态成员(JDK5)

final变量

  • final定义的变量必须在声明时对其赋值,除了修饰基本的数据类型,还可以修饰对象引用,如数组,一旦一个对象使用final修饰,它只能恒定指向一个对象,无法将其改变指向另一个对象。一个既是static有时final的字段是一段不能改变的存储空间
  • final定义的常量使用大写字母命名,中间使用下划线。final定义的变量不可改变,定义的引用不可改变,但是引用的值可以改变
  • final定义的值并不是恒定不变的,例如创建空白final值,在构造方法中对其赋值;对final成员变量赋值为随机值,每次创建新的对象都会有一个随机的final成员变量值(本质上是创建了新的对象,新的对象有了新的final值)
  • final可以修饰的数据
    • final修饰成员变量不可更改
    • final修饰成员变量定义为空白final,在构造方法中为空白final赋值
    • final参数,方法内不可改变参数的值
    • 方法内部设置局部变量为final,不可改变其值
package ex11_AdvancedClass;

import static java.lang.System.out;
import static java.lang.System.setOut;

import java.nio.file.FileAlreadyExistsException;
import java.util.Random;

class Test {
    int i = 0;
}

public class FinalData {
    private static Random rand = new Random(); //实例化一个Random类对象
    private final int VALUE_1 = 9;  //声明一个静态final常量,每个对象都有一份
    private final static int VALUE_2 = 10;  //声明一个final,static常量,归属于类,只有一份
    private final Test test = new Test();  //声明一个final引用
    private Test test2 = new Test();  //声明一个不是final的引用
    private final int[] a = {1, 2, 3, 4};  //声明一个定义为final的数组
    private final int a1 = rand.nextInt(10);
    private final static int a2 = rand.nextInt(10);

    private final int x;  //定义空白final,可在构造方法中初始化

    public FinalData(int y) {
        x = y;  //初始化空白final值
    }


    public static void main(String[] args) {
        FinalData data = new FinalData(1);
//        data.test = Test():  //使用final修饰的引用不可改变指向
        data.test.i = 5;  //不可改变引用,但可以改变引用的值(指向不可变,指向的内容可变)
        data.test2 = new Test();  //没有使用final修饰的引用可以改变指向
//        data.VALUE_1++;  //使用final修饰的变量不可改变
//        data.VALUE_2++;  //使用final修饰的静态变量不可改变,一般使用FinalData.VALUE调用
        data.a[0] = 9;    //不可改变引用,但可以改变引用的值
        out.println(data.a[0]);

        //其中的final x,a1随着新对象的创建都会改变
        //a2为final static,再次创建新对象并不会创建新区域,仍指向初始化时的区域,值也不会改变
        out.println("static a2: " + FinalData.a2);
        FinalData fdata = new FinalData(1);
        out.println("fdata.a1: " + fdata.a1 + " static fdata.a2: " + fdata.a2 + " fdata.x " + fdata.x);
        FinalData fdata2 = new FinalData(2);
        out.println("fdata2.a1: " + fdata2.a1 + " static fdata2.a2: " + fdata.a2 + " fdata2.x " + fdata2.x);
        
    }
}

final方法

  • final定义的方法不能被重写,是因为就是定义为不能重写
  • pravite定义的方法也不能被重写,是因为不能被类以外的区域访问,所以不能重写
    • 区别:pravite定义的方法被隐式的指定为final类型,final类型指定的方法不能被重写但是可以被子类对象向上转型后调用。pravite类型指定的方法被子类对象向上转型后不可调用,因为pravite就是定义了不能被本类以外的区域访问,子类也不可以

final类

final定义的类不允许被继承,类中的所有方法都被隐式的设置为final形式,但是类中的成员变量可以定义为final或非final形式

内部类

  • 成员内部类简介
    • 内部类可以随意使用外部类的成员变量和方法,即使是private
    • 内部类的对象必须绑定到外部类的对象上,内部类的对象与外部类的对象是相互依赖的
    • 实例化内部对象时不能在new操作符之前使用外部类名称实例化内部类对象,而是使用外部类的对象创建其内部类的对象
  • 内部类向上转型为接口
    • 在内部类中实现接口,定义改该内部类为private类型(非内部类不可以定义为private或protected),在外部类中定义一个public方法,该方法返回接口类型,返回对象时内部类对象,这样就实现了内部类对象向上转型为接口。如果某个类继承了外部类
    • 非内部类不能被声明为private或protected
  • 使用this关键字获取内部类和外部类的引用
    • 在内部类中使用this调用内部类对象的引用
    • 使用外部类.this调用外部类对象的引用
  • 局部内部类:在成员方法内定义内部类,如果需要在方法体内使用局部变量,需要设置成final类型,也即是在方法体内定义的内部类只能访问方法中final类型的局部变量,在内部类中,局部变量的值不可以改变。
  • 匿名内部类:创建一个实现接口的匿名类的对象,在匿名内部类定义结束后需要加分号标识,标识创建接口引用表达式的标识。
  • 静态内部类:内部类被声明为static
    • 如果创建静态内部类的对象,不需要外部类的对象
    • 不能从静态内部类的对象中访问非静态外部类的对象
    • 如果在每一个java文件中都设置一个主方法,将出现很多额外代码,而程序本身不需要这些主方法,为了解决这个问题,可以将主方法写入一个静态内部类中,编译后将生成一个名为<外部类$内部类>的独立类和<外部类>,只要使用<外部类$内部类>就可以运行主方法中的内容,完成测试后,需要将所有的class文件打包时只要伸出这个独立类即可
//成员内部类
package ex11_AdvancedClass;

public class OuterClass {  //外部类
    innerClass in = new innerClass();  //在外部类实例化内部类的对象引用

    public void outf() {
        in.inf();  //在外部类中调用内部类方法
    }

    public innerClass doit() {  //外部类方法
        //y=4;  //外部类不可以直接访问内部类的成员变量
        in.y = 4;  //可以通过对象访问
        return new innerClass();  //返回内部类的引用
    }

    class innerClass {  //内部类
        int y = 0;  //内部类成员变量

        public innerClass() {
        }  //内部类构造方法

        public void inf() {
        }  //内部类成员方法
    }

    public static void main(String[] args) {
        OuterClass out = new OuterClass();
        //内部类的对象实例化必须在外部类或外部类的非静态方法中实现
        //在其他地方实现需要使用外部类。
        //内部类实例一定要绑定到外部类的实例上,内部类对象依赖于外部类对象
        OuterClass.innerClass in3 = out.doit();  //out对象返回内部类的引用赋值给in
        //不能在new之前使用外部类名称实例化内部类对象,应该使用外部类的对象创建内部类的对象
        OuterClass.innerClass in2 = out.new innerClass();  //out对象创建一个新对象赋值给in2
        System.out.println(in3.y);
        System.out.println(out.in);
        System.out.println(out.in.y);  //out对象调用过doit()方法,把它的y值设置成了4
    }
}

//内部类向上转型为接口
package ex11_AdvancedClass;

interface OutInterface {
    public void f();
}

public class InterfaceInner {
    public static void main(String[] args) {
        OuterClass2 out = new OuterClass2();  //创建外部类对象
        OutInterface outinter = out.doit();  //使用外部类对象调用方法,返回内部类对象向上转型的接口
        outinter.f();  //使用接口调用f()方法
    }
}

class OuterClass2 {
    //定义一个内部类实现OuterInterface接口
    private class InnerClass implements OutInterface {
        public InnerClass(String s) {  //内部类的构造方法
            System.out.println(s);
        }

        public void f() {
            System.out.println("访问内部类的f()方法");
        }
    }

    public OutInterface doit() {  //定义一个外部类方法,返回值类型为OuterInterface接口类型
        return new InnerClass("访问内部类构造方法");  //内部类向上转型为接口
    }
}
//局部内部类
package ex11_AdvancedClass;

interface OutInterface2 {

}

class OuterClass3 {
    public OutInterface2 doit(String x) {
        //在doit()方法内定义一个内部类
        class InnerClass2 implements OutInterface2 {
            InnerClass2(String s) {
                s = x;  //内部类中使用局部变量必须是final变量或者实际上的final变量(不可变)
                System.out.println(s);
            }
        }
        return new InnerClass2("doit");
    }
}

public class Test2 {
    public static void main(String[] args) {
        OuterClass3 out3 = new OuterClass3();
        OutInterface2 outint = out3.doit("hi");

    }
}
//匿名内部类,创建一个实现接口的匿名类的对象
class OuterClass4 {
    public OutInterface2 doit() {  //定义doit()方法
        return new OutInterface2() {  //声明匿名内部类
            private int i = 0;
            public int getValue() {  //实现接口
                return i;
            }
        };  // 在匿名内部类定义结束后需要加分号标识,
    }
}
扫描二维码关注公众号,回复: 10151248 查看本文章
发布了46 篇原创文章 · 获赞 0 · 访问量 1027

猜你喜欢

转载自blog.csdn.net/weixin_37680513/article/details/103392656