本章内容

1.类与实例
2.方法
3.构造方法★★
4.方法重载Overload
5.对象
6.抽象类
7.接口
8.package包

1.类与实例

现实世界中,我们定义了“人”这种抽象概念,而具体的人则是“小明”、“小红”、“小军”等一个个具体的人。所以,“人”可以定义为一个类(class),而具体的人则是实例(instance)

类必须先定义才能使用。类是创建对象的模板,创建对象也叫类的实例化。instance是对象实例,instance是根据class创建的实例,可以创建多个instance,每个instance类型相同,但各自属性可能不相同,完整语法为:

1
2
3
4
5
6
7
8
9
10
11
12
[public][abstract|final]class<class_name>[extends<class_name>][implements<interface_name>] {
// 定义属性部分
<property_type><property1>;
<property_type><property2>;
<property_type><property3>;

// 定义方法部分
function1();
function2();
function3();

}

提示:上述语法中,中括号“[]”中的部分表示可以省略,竖线“|”表示“或关系”,例如 abstract|final,说明可以使用abstract或final关键字,但是两个关键字不能同时出现

对实例的说明:

  • public:表示“共有”的意思。如果使用public修饰,则可以被其他类和程序访问。每个Java程序的主类都必须是public类,作为公共工具供其他类和程序使用的类应定义为public类
  • abstract:如果类被abstract修饰,则该类为抽象类,抽象类不能被实例化,但抽象类中可以有抽象方法(使用abstract修饰的方法)和具体方法(没有使用abstract修饰的方法)。继承该抽象类的所有子类都必须实现该抽象类中的所有抽象方法(除非子类也是抽象类)
  • final:如果类被final修饰,则不允许被继承
  • class:声明类的关键字
  • class_name:类的名称
  • extends:表示继承其他类
  • implements:表示实现某些接口
  • property_type:表示成员变量的类型
  • property:表示成员变量名称
  • function():表示成员方法名称

2.方法

方法method是一段用来完成特定功能的代码块,类似于其它语言中的函数function。方法用于定义该类或该类的实例的行为特征和功能实现。

1
2
3
4
5
public class Test {
[public|private|protected][static]<void|return_type><method_name>([paramList]) {
// 方法体
}
}

方法返回值通过return语句实现,如果没有返回值,返回类型设置为void,可以省略return。return作用:1. 返回值 2.结束程序运行

各修饰符含义如下:

  • public、private、protected:表示成员方法的访问权限
  • static:表示限定该成员方法为静态方法
  • final:表示限定该成员方法不能被重写或重载
  • abstract:表示限定该成员方法为抽象方法。抽象方法不提供具体的实现,并且所属类型必须为抽象类

方法的参数有实参和形参之分,我们现在深入思考一下,方法中可以传递什么类型的值

  • 基本数据类型:整型,字符型,浮点型,布尔型

    1
    public static void test(int a, char b, double c, float d, boolean e){}
  • 引用数据类型:字符串,接口

    1
    public static void test(String a){}
  • 数组类型传递:

    1
    public static void test(int[] a, char[] b, double[] c,...){}
  • class类类型传递:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public static void test(employee a,employee b){}
    ...
    class employee{
    private int id;

    public int getId() {
    return id;
    }
    public void setId(int id) {
    this.id = id;
    }
    }

总结:
基本数据类型、引用类型在内存中的存储方式:

  • 基本数据类型:存放在栈内存中。用完就消失
  • 引用类型:在栈内存中存放引用堆内存的地址,在堆内存中存储类、对象、数组等。当没用引用指向堆内存中的类、对象、数组时,由 GC回收机制不定期自动清理

3.构造方法

构造方法是专门用来创建对象的方法,通过关键字new来创建对象,就是在调用构造方法
格式:public 类名称(参数类型 变量名称){方法体}

注意事项:

  • 构造方法的名称必须和所在的类名称完全一样,就连大小写也一样
  • 构造方法不要写返回值类型,连void都不要写
  • 构造方法不能return一个具体的返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class OOP {
public static void main(String[] args) {
// 在通过new操作符调用的时候,构造方法的参数数量、位置和类型一一对应
Person p = new Person("chd",18,10086);
System.out.println(p.getAge());
// 调用实例对象的属性
System.out.println(p.tel);
System.out.println(p.getAge());
System.out.println(p.getName());
}
}

class Person {
// 这个不能省略,用以声明变量
private String name;
private int age;
public int tel;

// 这就是Java的构造方法,类似于python的def __init__函数
public Person(String name, int age,int tel) {
this.name = name;
this.age = age;
this.tel = tel;
}

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

public int getAge() {
return this.age;
}
}

多构造方法

可以定义多个构造方法,在通过new操作符调用的时候,编译器通过构造方法的参数数量、位置和类型自动区分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public Person(String name) {
this.name = name;
this.age = 12;
}

public Person() {
}
}

如果调用new Person("Xiao Ming", 20);,会自动匹配到构造方法public Person(String, int)

如果调用new Person("Xiao Ming");,会自动匹配到构造方法public Person(String)

如果调用new Person();,会自动匹配到构造方法public Person()

4.Overload方法重载

这种方法名相同,但各自的参数不同(即参数数目不同,参数数据类型不同),称为方法重载(Overload)。注意:方法重载的返回值类型通常都是相同的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Hello {
public void hello() {
System.out.println("Hello, world!");
}

public void hello(String name) {
System.out.println("Hello, " + name + "!");
}

public void hello(String name, int age) {
if (age < 18) {
System.out.println("Hi, " + name + "!");
} else {
System.out.println("Hello, " + name + "!");
}
}
}

说明:

  • 声明为final的方法不能被重载。
  • 声明为static的方法不能被重载,但是能够被再次声明。

5.对象

对象创建方式:类名 对象名 = new 类名()

Java虚拟机在创建一个对象时都包含以下步骤:

  • 给对象分配内存。
  • 将对象的实例变量自动初始化为其变量类型的默认值。
  • 初始化对象,给实例变量赋予正确的初始值。

注意:每个对象都是相互独立的,在内存中占有独立的内存地址,并且每个对象都具有自己的生命周期,当一个对象的生命周期结束时,对象就变成了垃圾,由Java虚拟机自带的垃圾回收机制处理。

匿名对象

通过前面的知识我们已经了解到了,每次new都相当于开辟了一个新的对象,并开辟了一个新的物理内存空间。如果一个对象只需要使用唯一的一次,就可以使用匿名对象,匿名对象还可以作为实际参数传递。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Person {
public String name; // 姓名
public int age; // 年龄

// 定义构造方法,为属性初始化
public Person(String name, int age) {
this.name = name;
this.age = age;
}

// 获取信息的方法
public void tell() {
System.out.println("姓名:" + name + ",年龄:" + age);
}

public static void main(String[] args) {
new Person("张三", 30).tell(); // 匿名对象 => 姓名:张三,年龄:30
}
}

6.抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,那么这样的类称为抽象类。

抽象类:抽象方法所在的类,必须是抽象类才行,在class前写上abstract即可
抽象方法:就是在方法强加上abstract关键字,然后去掉大括号,直接分号结束

由于多态的存在,每个子类都可以覆写父类的方法,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person {
public void run() { … }
}

class Student extends Person {
@Override
public void run() { … }
}

class Teacher extends Person {
@Override
public void run() { … }
}

抽象方法的特征:

  • 抽象方法没有方法体
  • 抽象方法必须存在于抽象类中
  • 子类重写父类时,必须重写父类所有的抽象方法

抽象类的使用和定义规则:

  1. 不能直接创建new抽象类对象
  2. 必须用一个子类来继承抽象父类
  3. 子类必须覆盖重写抽象父类当中的所有抽象方法
  4. 创建子类实例对象进行使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class OOP{
public static void main(String[] args) {
/*
*这里值得值得注意:用abstract修饰的类就是抽象类。我们无法实例化一个抽象类
*/
Person p = new Student(); // 第四点:创建子类实例对象
p.age = 18;
p.run();

}
}

// 抽象类不仅要在类名前加abstract,也要在抽象方法名前加abstract
// Person类用abstract修饰的,表示为抽象类,我们无法实例化抽象类
abstract class Person{
protected int age;
public abstract void run();

}

// Student类继承Person类,并将父类的run方法进行重写
class Student extends Person{
@Override
public void run(){
System.out.println(super.age); // super指代父类
System.out.println(this.age);
}
}

注意事项:

  • 抽象类和抽象方法都要使用abstract关键字声明
  • 抽象方法只有声明没有实现,需要注意的是abstract关键字只能用于普通方法,不能用于static方法或者构造方法中
  • 在使用abstract关键字修饰抽象方法时不能使用private修饰,因为抽象方法必须被子类重写,而如果使用了private声明,则子类是无法重写的
  • 抽象类无法直接实例化(即className 变量名 = new className())

7.接口

含义

如果一个抽象类没有字段或者说没有属性,所有方法全部都是抽象方法,这时它可以被理解为一种特殊的类~接口(interface),所谓interface,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。因为接口定义的所有方法默认都是public abstract的,所以这两个修饰符不需要写出来(写不写效果都一样)

定义接口

1
2
3
4
5
[public] interface interface_name [extends interface1_name[, interface2_name,…]] {
// 接口体,其中可以包含定义常量和声明方法
[public] [static] [final] type constant_name = value; // 定义常量
[public] [abstract] returnType method_name(parameter_list); // 声明方法
}
  • public 表示接口的修饰符,当没有修饰符时,则使用默认的修饰符,此时该接口的访问权限仅局限于所属的包
  • interface_name 表示接口的名称。接口名应与类名采用相同的命名规则,大驼峰原则
  • extends 表示接口的继承关系
  • interface1_name 表示要继承的接口名称
  • constant_name 表示变量名称,一般是static和final型的,所以接口中的变量必须初始化
  • returnType 表示方法的返回值类型
  • parameter_list 表示参数列表,在接口中的方法是没有方法体的

接口对于其声明、变量和方法都做了许多限制,这些限制作为接口的特征归纳如下:

  • 具有public访问控制符的接口,允许任何类使用;没有指定public的接口,其访问将局限于所属的包
  • 方法的声明不需要其他修饰符,在接口中声明的方法,将隐式地声明为公有的(public)和抽象的(abstract)
  • 在Java接口中声明的变量其实都是常量,接口中的变量声明,将隐式地声明为 public、static 和 final,即常量,所以接口中定义的变量必须初始化
  • 接口没有构造方法,不能被实例化
  • 一个接口不能够实现(implements)另一个接口,但它可以继承(extends)多个其他接口,子接口可以对父接口的方法和常量进行重写

举例说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface A {
publicA(){…} // 编译出错,接口不允许定义构造方法
}

public interface StudentInterface extends PeopleInterface {
// 接口 StudentInterface 继承 PeopleInterface
int age = 25; // 常量age重写父接口中的age常量
void getInfo(); // 方法getInfo()重写父接口中的getInfo()方法
}

public interface MyInterface { // 接口myInterface
String name; // 不合法,变量name必须初始化
int age = 20; // 合法,等同于 public static final int age = 20;
void getInfo(); // 方法声明,等同于 public abstract void getInfo();
}

接口实现

接口的主要用途就是被实现类实现,一个类可以实现一个或多个接口,继承使用extends关键字,实现则使用implements关键字。因为一个类可以实现多个接口,这也是Java为单继承灵活性不足所作的补充。类实现接口的语法格式如下:

1
2
3
<public> class <class_name> [extends superclass_name] [implements interface1_name[, interface2_name…]] {
// 主体
}

实现接口需要注意以下几点:

  • 实现接口与继承父类相似,一样可以获得所实现接口里定义的常量和方法。如果一个类需要实现多个接口,则多个接口之间以逗号分隔
  • 一个类可以继承一个父类,并同时实现多个接口,implements 部分必须放在 extends 部分之后
  • 一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些抽象方法);否则,该类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象类

接口继承

一个interface可以继承自另一个interface。interface继承自interface使用extends,它相当于扩展了接口的方法。例如:

1
2
3
4
5
6
7
8
interface Hello {
void hello();
}

interface Person extends Hello {
void run();
String getName();
}

此时,Person接口继承自Hello接口,因此,Person接口现在实际上有3个抽象方法签名,其中一个来自继承的Hello接口。

8.package包

Java包的命名规范:

  • 包名全部由小写字母(多个单词也全部小写)
  • 如果包名包含多个层次,每个层次用“.”分割
  • 包名一般由倒置的域名开头,比如com.baidu,不要有www
  • 自定义包不能java开头
1
2
3
4
5
6
7
8
9
10
程序目录结构:
package_sample
└─ src
├─ com.hong
│ └─ Person.java
│ com.ming
│ └─ Person.java
└─ com.mr
└─ jun
└─ Arrays.java

使用import导入相关包

  • 方式一:import 包名.某一类名
  • 方式二:import 包名.*

 评论

联系我 | Contact with me

Copyright © 2019-2020 谁知你知我,我知你知深。此恨经年深,比情度日久

博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议