美文网首页
Java基础知识(二)

Java基础知识(二)

作者: CapybaraJ | 来源:发表于2018-07-06 17:34 被阅读0次

      主要讨论类的一些知识,Java比较繁琐的反射、lambda以及内部类不做涉及,这些东西要讲太复杂也太多了。

    目录


    • 关于类的基础常识
      • 类关系
      • Java访问修饰符
      • static在类中的应用
      • 文档注释
      • 阻止继承: final 类和方法
      • 常识与建议
    • 接口
      • 基础知识
      • 默认方法
      • 拷贝

    关于类的基础知识

    类关系

    类和类之间关系包括了 is a,has a,use a,三种关系
    is a包括了继承,实现关系,感觉是当中最重要的一个关系
    has a包括了组合,关联,聚合关系,表示A的对象包含B的对象。
    use a包括了 依赖关系,依赖关系的话,比较不推荐,就是说一个类的方法操纵另一类的对象,即为依赖
    关于它们的UML具体看 UML类图关系(泛化 、继承、实现、依赖、关联、聚合、组合)
    不过简单来讲,主要还是用到继承(直线+三角形)、接口实现(虚线+三角形)以及聚合关系(棱形+直线),注意方向。

    Java访问修饰符

    • private-仅对本类可见
    • public-对所有类可见
    • protected-对本包和所有子类可见
    • 默认无-本包可见

    static在类中的应用

    静态域

    静态域,即该类所有实例共享该域,比如类A有两个实例 A_1,A_2,两者的id域各有一个空间,但是count域共享。

    public class A
    {
      private static int count=0;
      
      private int id;
      ...
    }
    

    静态常量

    下面定义的volume就是静态常量啦,常量是由final决定的,但是static保证所有实例共用一个,当然没有也没啥,就浪费空间呗,而且使用static就可以用A.volume直接访问,不需要实例化。注意,是public域哦!

    public class A
    {
      private static int count=0;
      private int id;
      public static final int volume=502;
      ...
    }
    

    静态方法

    静态方法不许向对象实施操作。比如Math类的pow方法,计算时,将不会使用Math对象,说白了就是这个方法和这个类几乎没啥联系,并不访问实例域。我们可以直接调用A.getVolume(),不需要实例化,因为静态方法的特殊性,一般认为静态方法不会破坏对象,也就是比较安全的。

    public class A
    {
      private static int count=0;
      private int id;
      public static final int volume=502;
      ...
      public static getVolume(){
        return volume;
      }
    }
    

    工厂方法

    比如NumberFormat类使用工厂方法产生不同的类对象。

    NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
    NumberFormat percentFormatter = NumberFormat.getPercentInstance();
    

    当使用构造器的时候,是完全没有办法这么创建的哦。

    不需要使用对象调用静态方法,比如pow,比如main。

    文档注释

    一般的不说,比如\\,比如\**\这两种
    说一下 \**...*\这种

    通用注释

    /**
     * @author 作者
     * @since 起始版本
     * @version 版本
     * @deprecated (可选)
     * @see [类、类#方法、类#成员],也可以跟<a>标签,使用""的话,内容会被显示在see also上,可以有多个see also
     * {@link 规则同"@see"标记}
     */
    //具体例子
    /**
     * @author CapybaraJ
     * @since version 0.1.1
     * @version 0.1.3
     * @deprecated Use <code> getVolume_2(int) </code> instead
     * @see com.hostmann.corejava.A#getVolume()
     * {@link #getVolume_2(int)}
     */
    

    类注释

    /**
     * 类注释呢,用语句解释清楚这个类干嘛的
     * 可以分行的,也可以使用html标签
     * 虽然我没用过。。。
     * 每一行前面的*号可以没有,但是一般ide都会自己给你补
     */
    

    方法注释

    /**
     * 简要描述这方法干什么的
     * @param param1 解释param1代表啥balabala
     * @param param2 解释param2代表啥balabala
     * @return 返回值说明
     * @exception/throws 异常类型 异常说明
     */
    

    阻止继承: final 类和方法

    不允许扩展的类被称为 final 类 。 如果在定义类的时候使用了 final 修饰符就表明这个类是 final 类 。 例如 , 假设希望阻止人们定义Executive 类的子类, 就可以在定义这个类的时候 使用 final 修饰符声明 。 声明格式如下所示

    public final class Executive extends Manager
    {
      ...
    }
    

    类中的特定方法也可以被声明为 final 。 如果这样做 , 子类就不能覆盖这个方法, 例如:

    public class Employee
    {
      ...
      public final String getName()
      {
        return name;
      }
    }
    

    将方法或类声明为 final 主要目的是 : 确保它们不会在子类中改变语义 。 例如 , Calendar类中的 getTime 和 setTime 方法都声明为 final 。 这表明 Calendar 类的设计者负责实现 Date 类与日历状态之间的转换 , 而不允许子类处理这些问题 。 同样地, String 类也是 final 类, 这意味着不允许任何人定义 String 的子类 。 换言之 , 如果有一个 String 的引用, 它引用的一定是
    一个 String 对象 , 而不可能是其他类的对象 。

    抽象类

    常识与建议

    • 一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。所以传参时,如果是一个基础型变量,比如int,那么不会受到影响,但如果参数是一个类的引用,那么修改会直接作用到类上。
    • 一般对数据域采用getter/setter方法,并将数据域标记为private。
    • final实例域大多应用在基本类型域以及不可变类的域上,比如String类哇。final数据域必须初始化且无法更改。
    • final类和方法将会阻止继承,当然,类和方法被声明为final,域却不是哦。
    • 建议使用类名.静态方法的方法来调用静态方法,而不使用类实例。
    • 子类不能访问超类的私有域。
    • 子类的对象可以赋值给超类,而超类的对象不能赋值给子类,原因很简单,不能让子类对象操作超类实例,会出事。
    • 子类数组的引用可转换为超类数组的引用,但是也会有严重问题,因此不要随便转换。
    //经典职员-经理例子
    Manager[] managers = new Manager[10];
    Employee[] staff = managers; //OK
    staff[0] = new Employee(...); //woc,居然编译通过了 ERROR!!!
    //要知道,staff[0]的地址也是managers[0]的地址,我靠,一个普通员工成了mananger!!!
    
    • 包含一个或者多个抽象方法的类本身必须被声明为抽象的,但是抽象类不一定包含抽象方法。抽象方法再被extends时必须要被实现。
    • 抽象类虽然不能实例化,但是可以引用非抽象子类的实例。
    • 有时, 需要将 int 这样的基本类型转换为对象 。通常 , 这些类称为包装器 ( wrapper ) 。共有:Integer 、 Long 、 Float 、 Double 、 Short 、 Byte 、 Character 、 Void 和 Boolean ( 前6 个类派生于公共的超类 Number ) 。 对象包装器类是不可变的。举例:
      ArrayList <int> //wrong
      ArrayList <Integer> list= new ArrayList <> () ; //right

    接口

    基础知识

      接口不是类 , 而是对类的一组需求描述, 这些类要遵从接口描述的统一格式进行定义 。接口中的所有方法自动地属于 public 。 因此, 在接口中声明方法时 , 不必提供关键字public,不过 , 在实现接口时, 必须把方法声明为 public 。接口绝不能含有实例域!
    例子:

    //在 JavaSE 5.0 中, Comparable 接口已经改进为泛型类型 。
    public interface Comparable < T >
    {
      int compareTo (T other) ; // parameter has type T
    }
    

    在实现 Comparable < Employee > 接口的类中 , 必须提供下列方法
    int coirpareTo(Employee other)

    class Employee implements Comparable<Employee>
    {
      public int compareTo(Employee other)
      {
        return Double.compare(salary , other.salary);
      }
    }
    

    接口不是类, 尤其不能使用 new 运算符实例化一个接口 :
    x = new Comparable( . . . ) ; // ERROR
    然而, 尽管不能构造接口的对象, 却能声明接口的变量 :
    Comparable x ; // OK
    接口变量必须弓 I 用实现了接口的类对象 :
    x = new Employee ( ... ) ; //OK provided Employee implements Comparable
    接下来, 如同使用 instanceof 检查一个对象是否属于某个特定类一样, 也可以使用instance 检查一个对象是否实现了某个特定的接口 :
    if ( anObject instanceof Comparable ) { . . . }
    尽管每个类只能够拥有一个超类, 但却可以实现多个接口 。使用逗号将实现的各个接口分隔开 。

    默认方法

    可以为接口方法提供一个默认实现 。 必须用 default 修饰符标记这样一个方法 。这样我就不用所有的都覆盖,只用对我需要的覆盖。
    比如鼠标捕捉事件:

    必须全部覆盖重写 只需要对需要捕捉的事件重写

    如果先在一个接口中将一个方法定义为默认方法 , 然后又在超类或另一个接口中定义了同样的方法, 会发生什么情况 ? 诸如 Scala 和 C + + 等语言对于解决这种二义性有一些复杂的规则 。 幸运的是, Java 的相应规则要简单得多 。 规则如下 :
    1 ) 超类优先 。 如果超类提供了一个具体方法 , 同名而且有相同参数类型的默认方法会被忽略 。
    2 ) 接口冲突 。 如果一个超接口提供了一个默认方法 , 另一个接口提供了一个同名而且参数类型 ( 不论是否是默认参数 ) 相同的方法, 必须覆盖这个方法来解决冲突 。

    拷贝

    Cloneable 接口 , 这个接口指示一个类提供了一个安全的 clone 方法 。 由于克隆并不太常见 , 而且有关的细节技术性很强 ,所以不细讲。但是必须明确浅拷贝和深拷贝的概念。看图就很直白了。

    浅拷贝 浅拷贝代码 深拷贝代码

    相关文章

      网友评论

          本文标题:Java基础知识(二)

          本文链接:https://www.haomeiwen.com/subject/wmhtuftx.html