Java——第四章——类与对象之类的更多细节

一. 从方法返回值
方法语句执行完时,会到达一个 return 语句,或抛出异常;不管哪种情形,都会返回调用该方法的代码。方法声明中可以声明方法的返回类型。在方法体内使用 return 语句返回值。返回值类型必须与方法声明中的返回类型相同

返回类或接口
当方法使用类名作为返回类型时,返回的对象类型必须是该类本身或者其子类。
假设有如下方法,其声明为返回 Number 类:

public Number returnANumber(){
    //...
}

该技术叫做 协变返回类型 ,也就是说,返回类型可以是任意子类。

注意:返回类型也可以是接口名。这种情况下,返回的对象必须实现相应的接口。


二. 使用 this 关键字
this 关键字是当前对象(方法或构造器被调用的对象)的引用。在实例方法或构造器内部,可以使用 this 访问当前对象的所有成员。

(1).使用 this 与字段
使用 this 关键字的主要原因是方法或构造器的形参会覆盖相应的字段。如下代码:

public class Point{
    public int x = 0;
    public int y = 0;
    public Point(int a,int b){
        x = a;
        y = b; 
    }
}

使用 this 关键字可将代码改为:

public class Point{
    public int x = 0;
    public int y = 0;
    public Point(int x,int y){
        this.x = x;
        this.y = y; 
    }
}

构造器的每个参数都会覆盖对象的相应字段;

(2).联合使用 this 与构造器
从构造器内部使用 this 关键字可以调用同一个类的其他构造器。通常称这种做法为显式构造器调用。
这里给出的另一个 Rectangle 类,与之前给出的作比较:

public class Retangle {
    private int x,y;
    private int width,height;

    public Rectangle(){
        this(0,0,0,0);
    }
    public Rectangle(int width,int height){
        this(0,0,width,height);
    }
    public Rectangle(int x,int y,int width,int height){
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    ...
}

三.控制对类成员的访问
访问级别修饰符决定其他类是否可以访问特定字段、调用特定方法。访问控制有两个级别。

  • 顶级: public 或包级私有(无显式修饰符)
  • 成员级: public 、private、protected 或包级私有(无显式修饰符)

注意:访问级别有助于保证所定义的类为其他程序员所用,不会由于勿用而发生错误

  • 对各自的成员使用最为严格的访问级别。除非有足够的理由,否则都用 private
  • 除了常量,尽量避免 public 字段,使用 public 字段容易导致专门的实现,并限制代码的灵活性

这里写图片描述

四. 实例和类成员

(1).类变量
当多个类都创建自同一个类时,它们都有自己不同的实例变量副本。每个对象的这些变量都有自己的值,而且存储在不同的内存空间。
有时候需要有些变量对所有对象都公开,这可以由 static 修饰符实现。声明中有 static 修饰符的字段叫做 静态字段类变量。它们与类相关联,不与对象关联。类的每一个实例都共享一个类变量,该类变量存储在内存的固定位置。任何对象都能改变类变量的值。即使不创建这些实例,也有方法处理这些类变量。
举个例子,假设要创建多个 Bicycle 对象,并将他们从 1 开始编号。对象的 ID 唯一,因此是一个实例变量。同时需要一个字段来记录已创建的 Bicycle 对象数目,从而知道为下一个对象赋值哪个 ID。因此需要一个类变量 numberOfBicycle:

class Bicycle{
    private int cadence;
    private int gear;
    private int speed;
    //add an instance variable for the object ID
    private int id;
    //add a class variable for the number of Bicycle objects instantiated
    private static int numberOfBicycles = 0;
    ...
}

Bicycle 构造器课用于设置 ID 实例变量并递增 numberOfBicycles 类变量:

    //constructor
    public Bicycle(int startCadence,int startspeed,int startGear){
        gear = startGear;
        speed = startspeed;
        cadence = startCadence;
        //increment number of Bicycles and  assign ID number
        id = ++numberOfBicycles; 
    }
    public int getID(){
        return id;
    }

(2). 类方法
Java 程序语言也支持静态方法,跟支持静态变量一样。静态方法用 static 修饰符声明,可以直接用类名调用,无需创建类实例:

className.methodName(args)

静态方法也可用对象引用来引用:

instanceName.methodName(args)

但不推荐这种引用方式,因为这就不能清楚的表示它们是类方法

静态方法通常用于访问静态字段

public static void getNumberOfBicycles(){
    return numberOfBicycles;
}

(3).常量
联合使用 static 和 final 修饰符课定义常量。final 修饰符表示字段的值不能再更改。

static final double PI = 3.141592653589793;

五. 初始化字段
(1).静态初始化块
静态初始化块是以 static 关键字开头、卸载花括弧中的普通代码块:

static {
    //...
}

类可以包含任意多静态初始化块,且这些初始化可放置在类体的任何位置。
静态块亦可以通过另一种方式——私有静态方法来定义,私有静态方法的优点在于,需要重新初始化变量可以重用。

(2).初始化实例成员
实例变量通常在构造器中初始化,方法有两种:使用初始化块和使用 final 方法。

子类不能覆盖 final 方法。如果子类要重用初始化方法,final 方法就特别有用。

六. 嵌套类
嵌套类,也就是说,在类内定义另一个类。

class OuterClass{
    class NestedClass{
    }
}

定义
嵌套类有两种类型:静态和非静态。用 static 修饰符声明的嵌套类称为静态嵌套类;非静态嵌套类称为内部类。

嵌套类是其外部类的成员。非静态嵌套类(内部类)可以访问外部类的其他成员,即使他们被声明为 private。

(1).为什么使用嵌套类

  • 类的逻辑分类。如果类只对其它一个类有用,就可以将前者逻辑嵌入后者,将他们的代码放在一起,有助于保持包的线性结构。
  • 提高封装度。嵌套类的外部类成员用 private 声明,则对外界是隐藏的,而对内部类来说是可访问的,而且内部类对外界来说也是隐藏的。
  • 提高代码的可读性和可维护性

(2).静态嵌套类
与类方法一样,静态嵌套类与外部类也相关联,不能直接引用外部类的实例变量和方法,只能通过使用对象引用间接访问。
比如,要创建静态嵌套类的对象,要使用下述语法:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

(3).内部类
内部类可以直接访问对象的方法和字段。因为内部类与实例相关联,所以内部类本身不能定义任何静态成员。

要实例化内部类,首先实例化外部类。然后再外部对象中引用下述语法创建内部对象:

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

这里有一个数组例子来说明如何使用内部类。下面的例子创建了一个整形数组,并给数组元素赋值,然后按升序输出数组索引为偶数的元素值

public class DataStructure {
    //类变量
    private final static int SIZE = 15;
    private int[] arrayOfInts = new int[15];

    public DataStructure() {
        for(int i = 0;i < SIZE;i++){
            arrayOfInts[i] = i;
        }
    }

    public void printEven() {
        InnerEvenIterator iterator = this.new InnerEvenIterator();
        while(iterator.hasNext()){
            System.out.println(iterator.getNext() + " ");
        }
    }

    private class InnerEvenIterator{
        private int next = 0;

        public boolean hasNext(){
            return (next <= SIZE - 1);
        }

        public int getNext(){
            int retValue = arrayOfInts[next];
            next += 2;
            return retValue;
        }
    }

    public static void main(String[] args) {
        DataStructure ds = new DataStructure();
        ds.printEven();
    }
}
  • 外部类 DataStructure 包含两种方法,分别给数组元素赋值和打印索引为偶数的数组元素
  • 内部类 InnerEvenIterator 迭代成勋用于单步遍历数组结构,通常有测试最后一个元素、取当前元素、移至下一个元素等方法
  • main 方法实例化 DataStructure 对象(ds),并用于为整形数组 arrayOfInts 的元素赋值。然后调用方法 printEven 输出数组中索引为偶数的数组元素。

注意:内部类还有两种类型:局部内部类,它在方法体内声明;另一种叫匿名内部类,它也在方法体内声明,但不声明其名称。

七. 枚举类型
定义:枚举类型是那些字段由一组固定的常量组成的类型。常见的例子有指南针方向、星期几等。因为它们都是常量,所以枚举类型字段名都用大写字母表示。

Java 程序语言使用 enum 关键字定义枚举类型。例如,星期几的枚举类型课定义为:

public enum Day{
    SUNDAY,MONDAY,TUESDAY,WEDNESDAY,
    THURSDAY,FIRDAY,SATURDAY
}

Java 程序语言的枚举类型要比其他语言的对应概念更为强大。enum 声明定义了一个类(称为枚举类型)。枚举类型的类体可以包含方法和其他字段。创建枚举类型时,编译器会自动添加一些特殊的方法。如下所示为 Planet 类中的代码片段,它迭代太阳系的所有行星:

for(Planet p : Planet.values()){
    System.out.println("Your weight on %s is %f%n",p,p.surfaceWeight(mass));
}

注意:

  • 所有枚举类型都隐式继承 java.lang.Enum。因为 Java 不支持多重继承,所以枚举类型不能继承其他任何类。
  • 枚举类型的构造器必须是包级私有或私有的,它会自动创建枚举类型体的开端定义的常量,而且不能调用枚举类型的构造器本身。

八.注解
注解为程序提供数据,但不是程序本身的组成部分。他们不会直接音响他们注释的代码的行为。注解有很多用处:

  • 为编译器提供信息。可以使用注解检测错误或抑制警告
  • 编译时部署时处理。根据注解生成代码、XML 文件
  • 运行时处理。有些注解在运行时检查

注解可用于类、字段、方法、其他程序元素的声明中。注解总是最先指定,按照惯例总是写在单独的行上,而且可能包含哪些命名或未命名的值的元素:

@Author(
    name = "GiantDrawf",
    date = "7/12/2016"
)
class Myclass(){ }

(1). 文档
要使用注解添加相同的元数据,必须先定义注解类型:

@interface ClassPreamble {
    String author();
    String date();
    int currentRevision() default 1;
    String lastModified() default "N/A";
    String ;astModifiedBy() default "N/A";
    String[] reviewers();
}

注解类型的定义有点像接口的定义。在注解类型中。关键字 interface 写在 @ 字符后面。定义注解类型后,就可以使用该类型进行注解了,填入相应的值:

@ClassPreamble (
    author = "GiantDrawf",
    date = "5/12/2016",
    currentRevision = 6,
    lastModified = "7/12/2016",
    lastModifiedBy = "GiantDrawf",
    reviewers = {"Alice","Bob","Cindy"}
)
public class Generation3List extends Generation2List {
    //...
}

(2). 编译器使用的注解
三种注解类型:@Deprecated , @Override 和 @SuppressWarnings

@Deprecated 注解表示被标记的元素已被启用。程序使用带 @Deprecated 标记的方法、类和字段时,编译器就会发出警告

@Override 注解通知编译器钙元素覆盖了超类中声明的元素,覆盖方法时不一定要使用该注解,但它有助于降低错误率。如果被标记为 @Override 的方法不能正确覆盖其超类中的对应方法,编译器就会报错。

@SuppressWarnings 注解通知编译器忽略指定类型的警告。

(3).注解的处理
注解的更高级用法是编写注解器。注解处理器可以读取 Java 程序,并根据注解执行相应的操作。这里暂时不做总结。


由于之前学习过JavaScript,所以Java基础这块感觉还是可以很快入门。类和对象一块就算是学习的差不多了,还需要多一点代码实践来巩固,虽说定义都懂,但是实际应用中不免是有点小困难的,还需加油!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值