11 类的高级特性
11.1包
- 管理类文件的机制
11.1.1类名冲突
- 将两个名字相同需实现不同功能的类放在不同的包中
11.1.2完整的类路径
-
java.lang.Math
-
java.long是包名,Math是类的名称
-
java.util.Date date=new java.util.Date(); java.sql.Date date2=new java.sql.Date(233);
-
同一个包中类相互访问可以不指定包名
11.1.3创建包
- 在类中定义包名:package 包名
- 必须是类中的第一行非注释代码,指明包名后,包名成为类名的一部分,com.wsy.Dog
- 包名必须全部使用小写字母
- 避免包名重复:通常定义包名时使用创建者的Internet域名反序
11.1.4导入类包
-
使用import关键字导入包:
-
import com.wsy.*;//指定com.wsy包中的所有类在程序中都可以使用 import com.wsy.Math//指定com.wsy包中的Math类在程序中可以使用
-
当import了一个包中所有类,并不会import这个包的子包中的类,用包中的子类时需要再次对子包单独引用。
-
-
使用import导入静态成员
-
import static 静态成员
-
package com; import static java.lang.Math.max; import static java.lang.System.out; public class ImportTest { public static void main(String[] args){ out.println("1和4中的较大值为:"+max(1,4)); } }
-
11.2final变量
-
final用于变量声明,变量被设定后不可改变,通常由final定义的变量为常量
-
final double PI=3.14;//必须在声明时赋值
-
final还可修饰对象引用,例如数组
-
package com; import java.util.Random; import static java.lang.System.out; public class FinalStaticData { private static Random rand=new Random();//实例化一个Random类对象 private final int a1=rand.nextInt(10);//随机产生0-10间的随机数字赋予定义为final的a1 private static final int a2=rand.nextInt(10);//随机产生0-10间的随机数字赋予定义为static fianal的a2 public static void main(String[] args) { FinalStaticData fdata = new FinalStaticData(); out.println("重新实例化对象调用a1的值:" + fdata.a1); out.println("重新实例化对象调用a2的值:" + fdata.a2); FinalStaticData fdata2 = new FinalStaticData(); out.println("重新实例化对象调用a1的值:" + fdata2.a1); out.println("重新实例化对象调用a2的值:" + fdata2.a2); } }
-
final每次创建新对象都被 初始化,static final装载时被初始化
-
public static final定义全局常量, 这样的常量只能在定义时被赋值
-
11.3final方法
-
如果一个定义为private的方法隐式被指定为final类型,这样无需将一个private方法再定义为final类型
-
private final void test(){ ... }
-
-
作为final方法不能被覆盖,防止任何子类修改该类的定义与实现方式,private类型子类本身就不能修改,已经是final类型
-
package com; class Parents{ private final void doit(){ System.out.println("父类.doit()"); } final void doit2(){ System.out.println("父类.doit2()"); } public void doit3(){ System.out.println("父类.doit3()"); } } class Sub extends Parents{ public final void doit(){ System.out.println("子类.doit()"); } // final void doit2(){ //final方法不饿能覆盖 // System.out.println("子类.doit2()"); //} public void doit3(){ System.out.println("子类.doit3()"); } } public class FinalMethod { public static void main(String[] args){ Sub s= new Sub(); s.doit(); Parents p=s; //p.doit;//不能调用private方法 p.doit2(); p.doit3(); } }
-
p只能调用正常覆盖的doit3()方法,不能调用doit()方法,可见子类中的doit()方法只是生成了一个新方法而已,不是覆盖,而doit3()则是覆盖。
-
11.4final类
-
定义为final的类不能被继承,别人也不能对这个类有任何改动
-
final 类名{}
-
此时类中的所有方法都被隐式设置为final形式,但是final类中的成员变量可以定义成final或非final形式
11.5内部类
11.5.1成员内部类
-
package com; public class OuterClass { class innerClass { //内部类 innerClass() { //内部类构造方法 } public void inf() { } int y = 0; } innerClass in=new innerClass();//再外部类实例化内部类对象引用 public void outf(){ in.inf(); } public innerClass doit(){ //y=4; //外部类不可以直接访问内部类成员变量 in.y=4; return new innerClass(); } public static void main(String[] args){ //内部类的对象实例化必须在外部类或外部类中的非静态方法中实现 OuterClass out=new OuterClass(); OuterClass.innerClass in=out.doit(); OuterClass.innerClass in2=out.new innerClass();//不使用外部类名称,而使用外部类对象来创建内部类对象。称内部类实例一定要绑定在外部类的实例上。 } }
-
内部类向上转型为接口
-
package com; interface OutInterface {//定义一个接口 public void f(); } public class InterfaceInner { public static void main(String[] args){ OuterClass2 out=new OuterClass2(); OutInterface outinter=out.doit(); outinter.f(); } } class OuterClass2{ private class InnerClass implements OutInterface{ //定义一个内部类实现OuterInterface接口 InnerClass(String s){ //内部类构造方法 System.out.println(s); } public void f(){ System.out.println("访问内部类中的f()方法"); } } public OutInterface doit(){ return new InnerClass("访问内部类构造方法"); } }
-
好处:将权限为private的内部类向上转型为接口时,可以在外部提供一个接口,在接口中声明一个方法。在实现该接口的内部类中实现该接口的方法,就可以定义多个内部类以不同的方式实现接口中的同一个方法,而在一般的类中是不能多次实现接口中同一个方法的。
-
多用在Swing编程中,可以在一个类中做出多个不同的响应事件。
-
内部类权限为private,除OuterClass2可以访问该内部类外,其他类都不能访问,而可以访问doit()方法。该方法返回一个外部接口类型,这个接口可以作为外部使用的接口,包含一个f()方法,这个f()方法在继承此接口的内部类中实现。
-
如果某个类继承了外部类,内部的权限不可以向下转型为内部类InnerClass,同时也不能访问f()方法,但是却可以访问接口中的f()方法。
-
这样很好地对继承该类地子类隐藏了实现细节,仅为编写子类的人留下了一个接口和一个外部类,同时也可以调用f()方法,凡是f()方法的具体实现过程却被很好地隐藏了,这就是内部类最基本的用途。
-
利用接口隐藏具体实现细节
-
-
使用this关键字获取内部类与外部类的引用
-
package com; public class TheSameName { private int x; private class Inner{ private int x=9; public void doit(int x){ x++; //调用的是形参x this.x++; //调用内部类的变量x TheSameName.this.x++; //调用外部类的变量x } } }
-
11.5.2局部内部类
-
在类的局部位置定义内部类,例如类的方法中或任意的作用域
-
在方法中定义的内部类只能访问方法中的final类型的局部变量,因为在方法中定义的局部变量相当于一个常量,它的声明周期超出方法运行的生命周期。
-
inteface OutInterface2{ } class OuterClass3{ public OuterInterface2 doit(final Stringx){ class InnerClass2 implements OuterInterface2{ InnerClass2(String s){ s=x; System.out.println(s); } } return new InnerClass2("doit"); } }
11.5.3匿名类
-
class OuterClass4{ public OuterInterface2 doit(){ return new OuterInterface2(){ //声明匿名内部类 private int i=0; public int getValue(){ return i; } };//匿名内部类定义结束后,需要加分号标示,代表创建OuterInterface2引用表达式的标示。对应return。 } }
-
doit()方法首先返回一个OuterInterface2的引用,然后在return语句中插入一个定义内部类的代码,由于这个类没有名称,称其为匿名内部类。
-
匿名类编译后会产生以“外部类名$序号”为名称的.class文件,序号以1~n排列。
11.5.4静态内部类
-
package com; public class StaticInnerClass { int x=100; static class Inner{ void doitInner(){ // System.out.println("外部类"+x); } public static void main(String[] args){ System.out.println("a"); } } }
11.5.5内部类的继承
-
package com; public class OutputInnerClass extends ClassA.ClassB{//继承内部类B public OutputInnerClass(ClassA a){//硬性给予这个类一个带参数的构造方法,并且参数是继承的内部类的外部类的引用 a.super();//构造方法体写a.super();语句 } } class ClassA{ class ClassB{ } }