一、对象和类
1.定义
- 对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
- 类:类是一个模板,它描述一类对象的行为和状态。
类可以看成是对象的模板。
2.构造方法
每个类都有构造方法。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法。
在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。
下面是一个构造方法示例:
public class Puppy{
public Puppy(){
}
public Puppy(String name){
// 这个构造器仅有一个参数:name
}
}
3.创建对象
对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:
- 声明:声明一个对象,包括对象名称和对象类型。
- 实例化:使用关键字 new 来创建一个对象。
- 初始化:使用 new 创建对象时,会调用构造方法初始化对象。
public class Puppy{
public Puppy(String name){
//这个构造器仅有一个参数:name
System.out.println("小狗的名字是 : " + name );
}
public static void main(String[] args){
// 创建第一个Puppy对象
Puppy myPuppy = new Puppy( "Tommy" );
// 创建第二个Puppy对象
Puppy yourPuppy = new Puppy( "Bobby" );
// 创建第三个Puppy对象
Puppy hisPuppy = new Puppy( "Lucky" );
}
}
4.源文件声明规则
在本节的最后部分,我们将学习源文件的声明规则。当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则。
- 一个源文件中只能有一个 public 类
- 源文件的名称应该和 public 类的类名保持一致。例如:源文件中 public 类的类名是 Employee,那么源文件应该命名为Employee.java。
- 一个源文件可以有多个非 public 类
- 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。(package可以看成是文件的一个路径)
- 如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。
- import 语句和 package 语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
5.Java 包
包(类似于文件夹)主要用来对类和接口进行分类。当开发 Java 程序时,可能编写成百上千的类,因此很有必要对类和接口进行分类。
6.import 语句
在 Java 中,如果给出一个完整的限定名,包括包名、类名,那么 Java 编译器就可以很容易地定位到源代码或者类。import 语句就是用来提供一个合理的路径,使得编译器可以找到某个类。
二、继承
1.定义
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
生活中的继承:兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又是属于动物类。
所以继承需要符合的关系是:is-a,父类更通用,子类更具体。
2.类的继承格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类 {
}
class 子类 extends 父类 {
}
3.继承的作用
开发动物类,其中动物分别为企鹅以及老鼠,要求如下:
- 企鹅:属性(姓名,id),方法(吃,睡,自我介绍)
- 老鼠:属性(姓名,id),方法(吃,睡,自我介绍)
企鹅类:
public class Penguin {
private String name;
private int id;
public Penguin(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + ".");
}
}
老鼠类:
public class Mouse {
private String name;
private int id;
public Mouse(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + ".");
}
}
如果同时要在动物大类下,同时进行对企鹅类和老鼠类代码的编写,那么代码量就会庞大,此时,可以通过继承进行代码简化。
公共父类:
public class Animal {
private String name;
private int id;
public Animal(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + ".");
}
}
企鹅类和老鼠类:
public class Penguin extends Animal {
public Penguin(String myName, int myid) {
super(myName, myid);
}
}
public class Mouse extends Animal {
public Mouse(String myName, int myid) {
super(myName, myid);
}
}
4.继承的类型
Java不支持多继承,但支持多重继承
1.多重继承
public class A{......}
public class B extends A{......}
public class C extends B{......}
2.多继承
public class A{......}
public class B{......}
pulbic class C extends A,B{......}
5.继承的特性
-
子类拥有父类非 private 的属性、方法。
-
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
-
子类可以用自己的方式实现父类的方法。
-
Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
-
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
6.继承关键字
1)extends关键字
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
2)implements关键字
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。
如下 C类实现了A,B接口
public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B {
}
3)super、this关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
如果一个类没有明确指定访问修饰符(即没有写public
),那么它的访问级别就是默认的,这意味着这个类只能被同一个包内的其他类访问。
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Dog extends Animal { //定义一个名为Dog的类,这个类继承自Animal类
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal(); //创建一个Animal类的对象a
a.eat(); //调用a对象的eat方法
Dog d = new Dog(); //创建一个Dog类的对象d。
d.eatTest(); //调用d对象的eatTest方法。
}
}
输出结果:
animal : eat
dog : eat
animal : eat
4)final关键字
- 当
final
用来修饰一个类时,表明这个类不能被继承。换句话说,没有其他的类可以继承这个final
类。(final修饰的类不能作为父类) - 当
final
用来修饰一个方法时,表明这个方法不能被覆盖(Override)。也就是说,如果有其他的类继承了这个类,那么这个类中的final
方法是不能被子类重新定义的。 - 当
final
用来修饰一个变量时,表明这个变量的值一旦被初始化后,就不能被改变。
总的来说,final
关键字在Java中是用来限制类、方法或变量的行为的。它可以确保类不会被继承,方法不会被覆盖,以及变量的值不会被改变。
7.构造器
当父类有一个无参数的构造器时,子类构造器中可以不显式调用super()
,因为Java会自动调用父类的无参数构造器。然而,如果父类有一个带参数的构造器,并且没有无参数构造器,子类必须显式地通过super
关键字调用父类的构造器。
下面是一个父类构造器没有参数的例子:
// 父类
class Animal {
public Animal() {
System.out.println("Animal created");
}
}
// 子类
class Dog extends Animal {
public Dog() {
// 这里没有显式调用super(),但是Java会自动调用父类的无参数构造器
System.out.println("Dog created");
}
}
↑ 在这个例子中,创建Dog
对象时,会自动调用Animal
类的无参数构造器,然后调用Dog
类自己的构造器。
下面是一个父类构造器有参数的例子:
// 父类
class Animal {
public Animal(String name) {
System.out.println("Animal's name is " + name);
}
}
// 子类
class Dog extends Animal {
public Dog(String name) {
super(name); // 必须显式地通过super关键字调用父类的构造器,并提供参数
System.out.println("Dog's name is " + name);
}
}
↑ 在这个例子中,Animal
类只有一个带参数的构造器,没有无参数构造器。因此,Dog
类的构造器必须显式地调用super(name)
来传递参数给父类的构造器。
创建Dog
对象时,需要提供一个字符串参数,这个参数将被传递给Animal
类的构造器,然后Dog
类的构造器会继续执行。