Java 类和对象


类是创建对象的模板,类由属性和方法组成。


类的定义:

public class Pet {
  private String name;
  public Pet(String name) {
    this.name = name;
  }

  public String eat(String food) {
    return name + " eat " + food;
  }
}

在上面类的定义中 public class Pet {中的Pet是类名, private String name;定义了一个类属性,属性名为name,属性类型为String。 public Pet(String name){...}定义了一个类的构造方法,构造方法名Pet必须和类名一样,构造方法没有返回值。 public String eat(String food){...}定义了一个类方法eat,有一个参数,参数名为food,参数类型为String。方法的返回值类型为String。如果方法没有返回值,返回值类型则为void。

Java的类只能有一个父类,但可以实现多个接口。例如下面的类定义中Dog类继承Pet类,实现了Serializable和Comparable接口。

public class Dog extends Pet implements Serializable, Comparable<Dog>

命名规范:类名的第一个字符要大写,属性名和方法名的第一个字符要小写。


创建和使用对象

通过调用类的构造方法创建对象。

Pet pet = new Pet("Dog");创建一个Pet类型的对象,对象名为pet,构造方法的参数为"Dog"

下面是创建和使用对象的例子:

public class Pet {
    private String name;

    public Pet(String name) {
        this.name = name;
    }

    public String eat(String food) {
        return name + " eat " + food;
    }

    public static void main(String[] args) {
        Pet pet = new Pet("Dog");
        System.out.println(pet.eat("bones"));    // Dog eat bones
    }
}


类方法的定义和使用

方法的定义如public String eat(String food) throws Exception {方法体}包含六部分: 修饰符,可以为public、protected、private、static、final等。 方法的返回值类型,如String、int。如果没有返回值,返回值类型为void。 方法名,如eat。 参数列表,在()中,每个参数包含参数类型和参数名,多个参数使用逗号分隔。 例外列表,方法可以抛出多种例外。throws后跟例外类型。 方法体,在{}中。

方法名和参数类型组成方法签名。方法public String eat(String food) throws Exception {方法体}的签名为eat(String)

方法支持重载,即同一个类中可以包含多个相同方法名的方法,只要参数类型不同即可,即方法签名不同。

在方法参数的类型后加...,则方法参数可以接收不定个数的值。如方法public void eat(String... food)

下面是方法的定义和使用的例子。

public class Dog {
    private String name;

    public Dog(String name) {
        this.name = name;
    }

    public String eat(String food)  {
        return name + " eats " + food;
    }

    public String eat(String... foods)  {
        StringBuilder sb = new StringBuilder(name + " eat");
        for (String f : foods)
            sb.append(" ").append(f);
        return sb.toString();
    }

    public static void main(String[] args) {
        Dog pet = new Dog("Dog");
        System.out.println(pet.eat("bones"));    // Dog eats bones
        System.out.println(pet.eat("bones", "meat"));    // Dog eat bones meat
    }
}

嵌套类

嵌套类是定义在其它类(外部类)内部的类,嵌套类分为两种,静态嵌套类内部类(非静态类)。静态嵌套类的定义在class前面有static修饰符。

嵌套类,和外部类的属性和方法一样,是外部类的成员。静态嵌套类不能访问外部类的属性和方法。内部类可以访问外部类的属性和方法(包括private成员)。

嵌套类将关联性强的类组织在一起,增强了封装性。

静态嵌套类

同外部类的静态方法一样,静态嵌套类也不能访问外部类的类属性和方法。

下面是静态嵌套类的例子:

public class Pet2 {
    private String name;
    public Pet2(String name) {
        this.name = name;
    }

    static class Food {
        private String name;
        public Food(String name) {
            this.name = name;
        }
        public String getName() {
            //getPetName(); // error: 无法从静态上下文中引用非静态 方法 getPetName()
            return name;
        }
    }

    public String getPetName()  {
        return this.name;
    }

    public String eat(Food food)  {
        return name + " eat " + food.name;
    }

    public static void main(String[] args) {
        Pet2 dog = new Pet2("dog");
        Pet2.Food f = new Pet2.Food("bone");
        System.out.println(dog.eat(f));    // dog eat bone
    }
}

内部类

同外部类的实例属性和方法(非静态),内部类可以访问实例属性和方法。内部类不能定义静态的属性和方法。

下面是内部类的例子:

public class Pet3 {
    private String name;
    public Pet3(String name) {
        this.name = name;
    }

    class Food {
        private String name;
        public Food(String name) {
            this.name = name;
            System.out.println(getPetName());    // dog
        }
        public String getName() {
            return name;
        }
    }

    public String getPetName()  {
        return this.name;
    }

    public String eat(Food food)  {
        return name + " eat " + food.name;
    }

    public static void main(String[] args) {
        Pet3 dog = new Pet3("dog");
        Pet3.Food f = dog.new Food("bone");
        System.out.println(dog.eat(f));    // dog eat bone
    }
}

局部内部类

定义在方法中的内部类称为局部内部类:

下面是局部内部类的例子:

public class Pet4 {
    private String name;
    public Pet4(String name) {
        this.name = name;
    }

    public String getPetName()  {
        return this.name;
    }

    public String eat(String food)  {
        class Food {
            private String name;
            public Food(String name) {
                this.name = name;
                System.out.println(getPetName());    // dog
            }
            public String getName() {
                return name;
            }
        }

        Food f = new Food(food);
        return name + " eat " + f.getName();
    }

    public static void main(String[] args) {
        Pet4 dog = new Pet4("dog");
        System.out.println(dog.eat("bone"));    // dog eat bone
    }
}

匿名类

定义在方法中,没有类名的内部类称为匿名类。

下面是匿名类的例子:

public class Pet5 {
    private String name;
    public Pet5(String name) {
        this.name = name;
    }

    public String getPetName()  {
        return this.name;
    }

    interface Eatable {
        String eat(String food);
    }

    public String eat(String food)  {
        Eatable f = new Eatable() {
            public String eat(String food) {
                return food;
            }
        };

        return name + " eat " + f.eat(food);
    }

    public static void main(String[] args) {
        Pet5 dog = new Pet5("dog");
        System.out.println(dog.eat("bone"));    // dog eat bone
    }
}

Lambda表达式

Lambda表达式可以替代只有一个方法的匿名类。Lambda表达式的写法比较简洁。Lambda表达式常用来将功能当作参数传递给方法。

下面是Lambda表达式的例子:

import java.util.ArrayList;
import java.util.List;

public class LambdaExp {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("orange");

        list.stream().forEach(e -> System.out.println(e));    // apple orange
    }
}