java总结(之五)-- 类与接口、多态与继承

来源:互联网 发布:淘宝买家货到付款 编辑:程序博客网 时间:2024/05/22 02:30

访问权限控制

访问权限的等级,用包来划分:public、protected、包访问权限(就是没有关键字修饰)和private,依次降低。
作用域 当前类 同package 子孙类 其他package
public √ √ √ √
protected √ √ √ ×
friendly(default) √ √ × ×
private √ × × ×

上述四种访问权限,只有默认访问权限和public能够用来修饰类。修饰类的变量和方法四种权限都可以。(本处所说的类针对的是外部类,不包括内部类)

  • 默认访问权限(包访问权限):用来修饰类的话,表示该类只对同一个包中的其他类可见。
  • public:用来修饰类的话,表示该类对其他所有的类都可见

修饰类的方法和变量:

  • 默认访问权限(包访问权限):如果一个类的方法或变量被包访问权限修饰,也就意味着只能在同一个包中的其他类中显示地调用该类的方法或者变量,在不同包中的类中不能显示地调用该类的方法或变量。
  • private:如果一个类的方法或者变量被private修饰,那么这个类的方法或者变量只能在该类本身中被访问,在类外以及其他类中都不能显示地进行访问。
  • protected:如果一个类的方法或者变量被protected修饰,对于同一个包的类,这个类的方法或变量是可以被访问的。对于不同包的类,只有继承于该类的类才可以访问到该类的方法或者变量。
  • public:被public修饰的方法或者变量,在任何地方都是可见的。

注意一个.java源代码文件是一个编译单元。在编译单元内可以有一个public类,该类名必须与文件名相同,包括大小写。每个编译单元只能有一个public类,否则编译器不会接受。如果在该编译单元中还有额外的类的话,那么在包之外的世界无法看见这些类,他们主要为public类提供支持。java可运行程序是一组可以打包并压缩为一个java文档的.class文件。java解释器负责这些文件的查找、装载和解释。
java解释器的运行过程:首先,找出环境变量CLASSPATH包含一个或多个目录,用作查找.class文件的根目录。从根目录开始,解释器获取包的名称并将每个句点替换成反斜杠,以从CLASSPATH根中产生一个路径名称。得到的路径会与CLASSPATH中的各个不同项相连接,解释器就在这些目录中查找与创建的类名称相关的.class文件。

复用类类有两种方式:

  • 组合:只需在虚的类中产生现有类的对象。
  • 继承:采用现有类的形式在其中添加新代码。

组合

初始化类的对象有四种方式:只是保证你在用的时候已经被初始化。

  • 在定义对象的地方,也即是在构造器被调用之前被初始化。
  • 在类构造器中。
  • 就在要使用这些对象之前,也是惰性初始化。在生成对象不必每次都初始化情况下,可以减少额外负担。
  • 使用实例初始化。
    注意初始化顺序
    main—>加载器启动找.class文件—>加载基类—>依次顺序执行基类static块—>new 对象—>初始化为默认值(若是String则null,int为0等)—>先基类构造器再子类的,完成真正的初始化

继承

继承你可以继承了基类的所有字段和方法,你也可以修改和添加新的方法和字段。
初始化基类,在对基类子对象的正确初始化仅有一种方法来保证:在构造器中调用基类构造器来执行初始化,而基类构造器具有执行基类初始化所需的所有知识和能力。编译器会默认调用基类无参构造,若是有参构造必须显示super()调用。所以基类在导出类可以访问它之前就已经完成了初始化。

注意清理内存时,最好不要依赖垃圾回收器,一般它不会按你想的顺序去清理,而且它有可能永远都不会发生,编写自己的清理方法最好不要用finalize()因为它只有垃圾回收器启动时才会调用它。

在组合与继承之间选择

  • is-a(is-like-a)继承 有时需要转型时很有用! 继承表达行为间的差异。
  • has-a组合 组合表达状态上的变化
    组合是显式的在新类里放置子对象,而继承则是隐式的。组合通常用于想在新类里使用现有的类而非他的接口情形。
    一个最清晰的判断就是:看是否需要从新类向基类进行向上转型。如果必须向上转型,那继承是必须的;如果不需要就可以优先选择组合。

final关键字

  • static强调只有一份只会被初始化一次,final强调是个常量,在运行时被初始化可以在重新创建新对象时重新改变值,要是修饰为 static final 表示一个永不被改变的编译时常量,在装载时已经被初始化,而不是每次创建对象时都被初始化。
  • final修饰的方法。有两个原因:一是把方法锁定以防任何继承类修改它,也就是不可被覆盖。二是出于效率
  • final和private关键字。类中的所有private方法都隐式的制定为final也即是无法覆盖它。
  • final类。他所有的方法也默认为final。不可被继承。不希望他有子类。

多态

继承、封装、多态、抽象是面向对象的几大特征。
多态的实现多半是由后期绑定实现的,就是在运行时根据对象的类型进行绑定。java中除了static方法和final方法之外,所有方法都是后期绑定。多态是将改变的事物与未变的事物分离开来的重要技术。
多态只适用于普通方法,对于域和static方法包括构造器(是与类相关联的)不具备多态性。

接口

  • 抽象方法和抽象类。又要有抽象方法(没有方法体)该类就一定要声明为抽象类,但可以有非抽象方法,抽象类也可以没有抽象方法。抽象类中也可以有字段,抽象类相当于普通类+接口。如果从一个抽象类继承,就必须实现该抽象类中的所有抽象方法。如果不全实现那么这个类也是抽象类。
  • 接口。接口中也可以有域,但这些隐式的是static 和 final的。接口中没有普通方法必须为全是抽象方法,且为public,默认是public的,在接口中定义的方法要显示的为public否则权限就降低了。实现该接口必须实现所有抽象方法,
    使用接口的核心原因是:为了能够向上转型。其次是:防止客户端程序使用其创建对象。
    如果要创建不带任何方法定义和成员变量的而基类,就应该选择接口而不是抽象类,但恰当原则是优先选择类而不是接口,必要时我们应该重构接口而不是到处添加额外级别的间接性,接口只是一种重要的工具
  • extends。类是单继承关系。接口可以多继承。继承类、接口拥有父类所有方法和属性,你也可以覆盖原有的普通方法
  • implements。实现接口,必须实现接口中所有方法否则仍旧为抽象类。

内部类

内部类的对象的创建

内部类可以访问外部类对象所有成员,不需要任何特殊条件,拥有外部类的所有元素的访问权限。内部类的创建需要一个外部类对象的引用。

public class InnerClass {    void f(){System.out.println("out class.f()");}    public class Inner{        public InnerClass outer(){            return InnerClass.this;        }    }    public Inner inner(){return new Inner();}    public static void main(String[] args) {        InnerClass ic = new InnerClass();        InnerClass.Inner ii = ic.inner();        ii.outer().f();        InnerClass ic1 = new InnerClass();        InnerClass.Inner ii1 = ic1.new Inner();        ii1.outer().f();    }}output:out class.f()out class.f()

以上是创建内部类的两种方式,都必须使用外部类的对象引用。因此内部类对象就会暗暗的链接到创建它的外部类对象上。

匿名内部类

interface Contents{}public class NoNameClass {    //匿名内部类    public Contents contents(){        return new Contents(){            private int i = 11;            public int value(){return i;}        };    }    //与匿名内部类的等价的内部类    public class MyContents implements Contents{        private int i = 11;        public int value(){return i;}    }    public static void main(String[] args) {        NoNameClass nc = new NoNameClass();        Contents contents = nc.contents();    }}

匿名内部类使用了默认构造器并且继承自Contents并返回Contents的向上转型的引用。如果定义一个匿名内部类,并且希望它使用一个在外部定义的对象,那么编译器会要求器参数是final的。匿名内部类既可以扩展类也可以实现接口但不能兼备,而且如果实现接口也只能实现一个。

嵌套类

如果不需要内部类对象与其外围类之间有联系,那么可以将内部类声明为static,这通常就是嵌套类。嵌套类具有:

  • 要创建嵌套类的对象,并不需要外围类的对象。
  • 不能从嵌套类的对象中访问非静态的外围类对象。
  • 嵌套类与普通内部类区别,普通内部类的字段与方法,只能放在类的外部层次上,所以普通内部类不能有static数据和static字段,也不能包含嵌套类。而嵌套类却不受限制。

局部内部类

局部内部类不能有访问权说明符,因为他不是外围类的一部分,但是它可以访问当前代码块内的常量,以及外围类的所有成员。就就是局部内部类的名字在方法外是不可见的。

内部类的好处

  • 内部类继承或者实现某个接口,内部类的代码操作创建它的外围类的对象,所以内部类提供了某种进入外围类的窗口。

  • 每个内部类都能独立的继承自一个接口的实现,无论外围类是否已经继承了某个接口的实现,对于内部类是没有影响的。同时也实现的多重继承。

  • 在单个外围类中,可以让多个内部类以不同方式实现同一个接口或继承同一个类。
  • 内部类没有令人迷惑的is-a关系它只是一个独立的实体。
  • -

枚举类型

关键字enum可以将一组具有名的值得有限jihe 创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用。枚举类型除了不能继承外,其他与普通类一样,也可以有自己的方法,甚至main方法,也可以有自己的构造器(private或包权限)

enum Color1{YELLOW,RED,GREEN}public class EnumTest {    Color1 color1 = Color1.RED;    public void change(){        switch (color1) {        case YELLOW:            color1 = Color1.RED;            break;        case RED :            color1 = Color1.GREEN;            break;        case GREEN :            color1 = Color1.YELLOW;            break;        }    }    @Override    public String toString() {        return "the color is:"+color1;    }    public static void main(String[] args) {        for (Color1 string : Color1.values()) {            System.out.println(string + "ordinal:" +string.ordinal());            System.out.println(string.getDeclaringClass()+"---"+string.name());        }        EnumTest enumTest = new EnumTest();        for(int i = 0;i<7;i++){            System.out.println(enumTest);            enumTest.change();        }    }}output:YELLOWordinal:0class container.Color1---YELLOWREDordinal:1class container.Color1---REDGREENordinal:2class container.Color1---GREENthe color is:REDthe color is:GREENthe color is:YELLOWthe color is:REDthe color is:GREENthe color is:YELLOWthe color is:RED

enum实现了Comparable接口所以具有compareTo()方法,可以用ordinal()方法返回次序。而且enum也经常用在switch语句中。

public enum Color {    RED("hongse"), DARK("shense"),BLACK("heise");    private String description;    private Color(String description){this.description = description;}    public String getDescription(){return description;}    public static void main(String[] args) {        for (Color string : Color.values()) {            System.out.println(string +":"+string.getDescription());        }    }}output:RED:hongseDARK:shenseBLACK:heise

注意如果打算定义自己的方法,那么必须在enum实例序列最后添加分号。java要求必须先定义enum实例。

EnumSet

enum要求其成员不能重复,所以enum看起来具有Set集合的行为,但是不能从enum中删除或者添加元素,引入EnumSet来替代enum,EnumSet是非常快速,他在说明一个二进制位是否存在时具有很好的表达,性能也很高。EnumSet的元素必须来自一个enum。

enum Colors{YELLOW,RED,GREEN}public class EnumSetTest {    public static void main(String[] args) {        EnumSet<Colors> eSet = EnumSet.noneOf(Colors.class);        eSet.add(Colors.YELLOW);        eSet.add(Colors.RED);        System.out.println(eSet);    }}
0 0
原创粉丝点击