Java笔记--类与对象


Java笔记–类与对象

面向过程:当要实现一个功能的时候,每一个具体步骤都要亲历亲为,详细处理每一个细节。

面向对象:当实现一个功能不关心具体步骤,而是我一个已经具有该功能的人来帮我做事。

类:一组相关属性和关系行为的集合,可以看成是一类事物的模板,使用事务的属性特征和行为特征来描述该类事务

  • 属性:该事务的状态信息/特征描述信息。
  • 行为:该事务能够做什么。

类与对象的关系

  • 类是对一类事物的描述,是抽象的。
  • 对象是一类实物的实例,是具体的。
  • 类是对象的模板,对象是类的实体。

类的定义

定义一个类用来模拟”学生“事物,其中就有两个组成成分:

属性(是什么):

姓名

年龄

行为(能做什么):

吃饭

睡觉

学习

对应到java的类当中:

成员变量(属性):

String name//姓名

int age//年龄

成员方法(行为)://没有static

public void eat () {};

public void sleep() {};

public void study() {};

【注意事项】

1、成员变量是直接定义在类当中的,在方法外边。

2、成员方法不要写static关键字。

public class Student {
    //成员变量
    String name;//方法外定义的变量
    int age;

    //成员方法
    public void eat(){
        System.out.println("吃饭饭!");
    }
    public void sleep(){
        System.out.println("睡觉觉!");
    }
    public void study(){
        System.out.println("学习!");
    }
}

通常情况下,一个类并不能直接使用,需要根据类创建一个对象才能使用。

1、导包:指出需要使用的类在什么位置。

import 包名称.类名称

import cn.cikeshijia.Demo02.Student

对于和当前类属于同一个包的情况,可以省略导包语句不写。

2、创建,格式

类名称 对象名 = new 类名称();//对象名可以看作变量名

Student stu = new Student();//根据Student类创建了一个stu的对象

3、使用:分两种情况

使用成员变量:对象名.成员变量名

使用成员方法 :对象名.成员方法名(参数)

(也就是想用谁,就用对象名.谁)

【注意事项】

==如果成员变量没有进行赋值==,那么将有一个默认值,规则和数组一样。

//1、导包
//我需要的Student类,和我自己位于同一个包下,所以额可以省略导包语句不写
import cn.cikeshijia.Demo02.Student;
public class Demo02Student {
    public static void main(String[] args) {

        //2、创建
        //类名称 对象名 = new 类名称();
        Student stu =new Student();

        //3、使用
        //对象名.成员变量名
        System.out.println(stu.name);
        System.out.println(stu.age);

        stu.name = "鞠婧祎";
        stu.age = 29;

        System.out.println(stu.name);
        System.out.println(stu.age);
        System.out.println("===========");

        //对象名。成员方法名()
        stu.eat();
        stu.sleep();
        stu.study();
    }
}

面向对象的三大特征:封装、继承、多态

封装

封装性在java当中的体现。

1、方法就是一种封装

2、关键字Privote也是一种封装

用private关键字将需要保护的成员变量进行修饰

一旦使用了private关键字进行修饰,那么本类中当然可以随意访问。

但是!超出了本类范围之外就不能随意访问了。

间接访问private成员变量,就是定义一对儿getter/setter方法。

在方法中可以对输入/输出数据进行处理。

必须叫setxxx或者是getxxx命名规则

  • 对于getxxx来说,不能有参数,返回值类型和成员变量对应
  • 对于setxxx来说,不能有返回值,参数类型和成员变量对应

this关键字

当方法的局部变量和类的成员变量重名的时候,根据“就近原则”,优先使用局部变量。

当需要访问本类中的成员变量,需要使用格式:
this.成员变量名

++通过谁调用的方法,谁就是this++

构造方法

构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象的时候其实就是在构造方法。

//格式
public 类名称(参数类型 参数名称){
    方法体
}

【注意事项】

1、构造方法名称必须与所在类名称完全一样,就连大小写也要一样。

2、构造方不要写返回值类型,连void都不写。

3、构造方法不能return一个具体的返回值。

4、如果没有编写任何构造方法,那么编译器将会默认赠送一个构造方法,没有参数、方法体,什么都不做。
5、一旦编写了至少一个构造方法,那么编译器将不在赠送。
6、构造方法也是可以重载的。
重载:方法名称相同,参数列表不同。

一个标准类

一个标准的类通常要拥有下面四个组成部分:

1、所有的成员变量都要用 ==private== 关键字修饰

2、为每一个成员变量编写一对儿 ==getter/setter== 方法

3、编写一个无参数的构造方法

4、编写一个全参数的构造方法

一个标准的类也叫做Java Bean

Student类

/*
一个标准的类通常要拥有下面四个组成部分:
1、所有的成员变量都要用private关键字修饰
2、为每一个成员变量编写一对儿getter/setter方法
3、编写一个无参数的构造方法
4、编写一个全参数的构造方法

一个标准的类也叫做Java Bean
*/
public class Student {

    private String name;//姓名
    private int age;//年龄

    public Student() {//无参构造函数
    }

    public Student(String name, int age) {//全参构造函数
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

主函数

public class Demo03Student {
    public static void main(String[] args) {
        Student stu1 =new Student();//创建
        stu1.setName("迪丽热巴");
        stu1.setAge(18);
        System.out.println("姓名:"+stu1.getName()+"。年龄:"+ stu1.getAge());
        System.out.println("===========华丽的分割线=========");

        Student stu2 = new Student("古力娜扎",20);
        System.out.println("姓名:"+stu2.getName()+"。年龄:"+ stu2.getAge());
        stu2.setAge(21);
        System.out.println("姓名:"+stu2.getName()+"。年龄:"+ stu2.getAge());
    }
}

继承

继承是多态的前提,没有继承就没有多态。

继承主要解决的问题就是共性抽取

父类(基类、超类)

子类(派生类)

继承关系当中的特点:

  1. 子类可以拥有父类的“内容”
  2. 子类还可以拥有自己专有的内容。

在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当作父类看待

例如父类是员工,子类是讲师,那么讲师就是一个“员工”。关系:is-a。

定义方法

//定义父类格式:(一个普通的类定义)
public class 父类名称{
    //……
}

//定义子类格式:
public class 子类名称 extends 父类名称{
    //……
}

多个变量重名时,变量调用

在父子类的继承关系当中,如果成员变量==重名==,则创建子类对象时,访问有两种方式:

  • 直接通过子类对象访问成员变量:
    等号左边是谁,就优先用谁,没有则向上找。
  • 间接通过成员方法访问成员变量:
    该方法属于谁, 就优先用谁,没有则向上找。
/*
局部变量:       直接写成员变量名

本类的成员变量: this.成员变量名

父类的成员变量: super. 成员变量名
*/

访问成员方法的规则:

在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有则向上找。

【注意事项】

++无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。++

重写(Override)

概念:在继承关系当中,方法的名称一样,参数列表也一样。

重写(Override) : 方法的名称一样,参数列表【也一样】。覆盖/覆写

重载(Overload) : 方法的名称一样,参数列表【不一样】。

方法的覆盖重写特点:

创建的是子类对象,则优先用子类方法。

方法覆盖重写的注意事项:

  1. ==必须保证父子类之间方法的名称相同,参数列表也相同。==

    @Override:写在方法前面,用来检测是不是有效的正确覆盖重写。

    这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。

  2. ==子类方法的返回值必须【小于等于】父类方法的返回值范围。==

小扩展提示: java. lang. object类是所有类的公共最高父类(祖宗类),
java. lang.String就是object的子类。

  1. ==子类方法的权限必须【大于等于【父类方法的权限修饰符。==

小扩展提示: public > protected > (default) > private

备注: (default)不是关键字default,而是什么都不写,留空。

覆盖重写的应用

对于方法的重写,需要新功能,又不能舍弃旧功能。定义一个子类方法,将需要的新的方法加入,并引用子类方法。super.旧方法( );

构造方法

继承关系中,父子类构造方法的访问特点:

  1. 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。
  2. 子类构造可以通过super关键字来调用父类重载构造。
  3. super的父类构造调用,必须是子类构造方法的第一个语句。 不能一个子类构造调用多次super构造。

总结:
子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。

super关键字的用法有三种:

  1. 在子类的成员方法中,访问父类的成员变量。
  2. 在子类的成员方法中,访问父类的成员方法。
  3. 在子类的构造方法中,访问父类的构造方法。

this关键字的用法有三种:

  1. 在本类的成员方法中,访问本类的成员变量。
  2. 在本类的成员方法中,访问本类的另- -个成员方法。
  3. 在本类的构造方法中,访问本类的另一个构造方法。

==在第三种用法当中要注意:==

A. this(… )调用也必须是构造方法的第一个语句, 唯一一个 。

B. super和this两种构造调用,不能同时使用。

总结

  1. Java语言是==单继承==的。

    一个类的直接父类只能有唯一一个。
  2. Java语言可以==多级继承==。

    我有一个父亲,我父亲还有一个父亲,也就是爷爷。

    java.lang.object:Java中的祖宗类。
  3. 一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类。

    可以有很多个兄弟姐妹,生二胎。

抽象

==抽象方法:== 就是加上abstract关键字,然后去掉大括号,直接分号结束。

==抽象类:== 抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。

如何使用抽象类和抽象方法:
  1. 不能直接创建new抽象类对象。
  2. 必须用一个子类来继承抽象父类。
  3. 子类必须覆盖重写抽象父类当中所有的抽象方法。

覆盖重写(实现): 子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
4. 创建子类对象进行使用。

public abstract class Animal {
    //这是一个抽象方法,代表吃东西,但是具体吃什么(大括号的内容)不确定。
    public abstract void eat();

    //这是普通的成员方法
    public void normalMethod() {
    }

public class Cat extends Animal {
    @Override
    public void eat(){
        System. . out. println( "猫吃鱼");
    }
注意事项

关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,无需死记硬背。

  1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

理解: 假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。

  1. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。

理解: 子类的构造方法中,有默认的super(),需要访问父类构造方法。

  1. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

理解: 未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。

  1. 抽象类的子类,必须重写抽象父类中==所有的==抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。

理解: 假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。


多态

代码当中体现多态性,其实就是一句话。父类引用指向子类对象。

继承是多态的前提。

多态指:一个方法有多种状态。

格式:

父类名称 对象名= new子类名称();

或者:

接口名称对象名= new实现类名称();

此时就是将子类对象当作父类进行使用

访问成员对象

访问成员变量的两种方式:

  1. 直接通过对象名称访间成员变量,看等号左边是谁,优先用谁,没有则向上找
  2. 间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则向上找

访问成员方法

在多态的代码中,成员方法的访问规则是:

看new的是谁,就优先用谁,没有则向上找

口诀:编译看左边,运行看右边

  • 在编译时,看父类方法,如果父类方法没有,就会报错。在运行时,看子类方法,运行子类方法里面有的对象。
  • 也就是说,只有子类里面对父类重写的方法才有用。
    注:成员变量编译看左边,运行还看左边。

使用多态的好处

//如果不用多态,只用子类,那么写法是:
Teacher one = new Teacher();
one.work();//讲课
Assistant two = new Assistant(;
two.work();//辅导

我现在唯—要做的事情,就是调用work方法,其他的功
能不关心。

//如果使用多态的写法,对比一下:
Employee one = new Teacher();
one.work();//讲课
Employee two = new Assistant();
two.work()://辅导

好处:无论右边new的时候换成哪个子类对象,等号左边调用方法都不会变化。

对象的 ++向上转型++

对象的向上转型,其实就是多态写法;格式:

父类名称 对象名 = new 子类名称();

含义:右侧创建了一个子类对象,把他当作父类来看待使用。

Animal animal = new Cat();//创建了一只猫当做动物看待

【注意事项】==向上转型一定是安全的==。从小范围转向了大范围,从小范围的猫,向上转换成为更大范围的动物。

类似于:

double number = 100;//int-->double自动类型转换。

向上转型一定是安全的,没有问题的,正确的。但是也有一个 弊端: 对象—旦向上转型为父类,那么就无法调用子类原本特有的内容。

解决方案:用对象的向下转型【还原】

对象的 ++向下转型++

对象的向下转型,其实是一个【还原】的动作。

格式:

子类名称 对象名 = (子类名称) 父类对象;

含意:将父类对象,【还原】成为本来的子类对象。

Animal animal = new Cat();//本来是猫,向上转型成为动物
Cat cat = (Cat) animal://本来是猫,已经被当做动物了,还原回来成为本来的猫

注意事项:

a. 必须保证对象本来创建的时候,就是猫,才能向下转型成为猫。

b. 如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错(编译不会报错,运行会出现异常[ClassCastException])。

类似于:

int number = (int)10.0;//int-->double自动类型转换。
int number = (int)10.5;//不可以,精度损失

instanceof关键字

如何才能知道一个父类引用的对象,本来是什么子类?
格式
对家instanceof类型
这将会得到一个booLear值结果,也就是判断前面的对象能不能当做后面类型的实例。

public class Demoe2Instanceof {
    public static void main(String[] args){
        Animal animal = new  Cat();//本来是一只猫
        animal.eat();//猫吃鱼
        //如果希望掉用子类特有方法,需要向下转型
        //判断一下交类引用animat本来是不是Dog
        if(animal instanceof Dog) {
            Dog dog = (Dog)animal;
            dog.watchHouse();
        }
        //判断一下animaL本来是不是cat
        if (animal instanceof Cat) {
            cat cat = (cat)animal;
            cat.catchMouse();
        }
    }
}

向下转型一定要进行instanceof判断以免出错


静态字段与静态方法(利用static关键字)

如果一个成员变量使用了static关键字,那么这个变量不再属于对象自己,而是属于所在的类。多个对象共享同一份数据。

public class Demo01StaticField {

    public static void main(String[] args) {
        Student one = new Student("郭靖" , 19);
        one.room = "101教室";
        System.out.println("姓名:"+ one.getName() +
                ", 年龄:" + one.getAge() + ", 教室:"+one.room +
                ",学号:" + one.getId());

        Student two = new Student("黄蓉",16);
        System.out.println("姓名:"+ two.getName() +
                ", 年龄:" + two.getAge() + ", 教室:"+one.room +
                ",学号:" + two.getId());
    }

}

Student类

public class Student {
    private int id;//学号
    private String name;//姓名
    private int age;//年龄
    static String room;//教室
    private static int idCounter = 0;//学号计数器,每当new了一个新对象的时候计数器++

    public Student() {
        this.id = ++idCounter;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        this.id = ++idCounter;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

static修饰成员

一旦使用static修饰成员方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类的。

如果没有static关键字,那么必须首先创建对象,然后通过对象才能使用它。

如果有了static关键字,那么不需要创建对象,直接就能通过类名称来使用它。

无论是成员变量,还是成员方法。如果有了static,都推荐==使用类名称进行调用==。

  • 静态变量:类名称.静态变量
  • 静态方法:类名称.静态方法()

【注意事项】

  1. 静态不能直接访问非静态。
    原因:因为在内存当中是[先]有的静态内容,[后] 有的非静态内容。

    “先人不知道后人,但是后人知道先人。”
  2. 静态方法当中不能用this.

    原因: this代表当前对象, 通过谁调用的方法,谁就是当前对象。
public class Demo02StaticMethod {
    public static void main(String[] args) {
        MyClass obj = new MyClass(); //首先创建对象
        //然后才能使用没有static关键字的内容
        obj.method();

        //对于静态方法来说,可以通过对象名进行调用,也可以直接通过类名称来调用。
        obj.methodStatic(); //正确,不推荐,这种写法在编译之后也会被javac翻译成为“类名称.静态方法名”
        MyClass . methodStatic(); //正确,推荐

        //对于本来当中的静态方法,可以省略类名称
        myMethod();
        Demo02StaticMethod.myMethod(); //完全等效
    }

    public static void myMethod() {
        System. out. println("自己的方法! ");
    }

}

MyClass类

public class MyClass {
    int num; //成员变量
    static int numStatic; //静态变量
    //成员方法
    public void method() {
        System. out . println("这是一个成员方法。 ");
    //成员方法可以访问成员变量
        System. out . println(num);
    //成员方法可以访问静态变量
        System. out . println(numStatic);
    }
    //静态方法
    public static void methodStatic() {
        System. out. println("这是一个静态方法。");
        //静态方法可以访问静态变量
        System. out. println(numStatic);
        //静态不能直接访问非静态[重点]
//      System. out. println(num); //错误写法!
        //静态方法中不能使用this关键字。
//      System. out.println(this); //错误写法!

    }

}

静态代码块

静态代码块的格式是:


public class 类名称{
    static {
        //静态代码块的内容
    }
}

特点:当第一次用到本类时,静态代码块执行 ==唯一== 的一次。

静态内容总是优先于非静态,所以静态代码块==比构造方法先执行==。

静态代码块的典型用途:
++用来一次性地对静态成员变量进行赋值。++

public class Demo04Static {

    public static void main(String[] args) {
        Person one = new Person();
        Person two = new Person();
    }

}

Person类

public class Person {

    static{
        System.out.println("静态代码块执行!");
    }
    public Person() {
        System.out.println("构造方法执行! ");
    }
}

final

finaL关键字代表最终的、不可改变的。
常见四种用法:

  1. 可以用来修饰—个类
  2. 可以用来修饰—个方法
  3. 还可以用来修饰一个局部变量
  4. 还可以用来修饰一个成员变量

1. 可以用来修饰—个类

当finaL关键字用来修饰一个类的时候,格式:

public finaL cLass 类名称{
    //...
}

含义:当前这个类不能有任何的子类。(太监类〕

注意:一个类如集是final的,那么其中所有的成员方法都无法进行覆盖重写(因为没儿子)

public final class MyClass f*extends object*/ {

2. 可以用来修饰—个方法

当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写。
格式:

修饰符finol 返回值类型 方法名称(参数列表){
    //方法体
}

【江意事项】

对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。

3. 还可以用来修饰一个局部变量

一旦使用finaL用来修饰局部变量,那么这个变量就不能进行更改。

  • “一次赋值,终生不变”

  • 定义的实体存储地址不发生改变。

    pubiic class DemoFinal {
      public static void main(String[] args) {
          int num1 = 10;
          System.out.println(num1);//10
          num1 = 20;
          System.out.println(num1); //20
          //一旦使用final用来修饰局部变量,那么这个变量就不能进行更改。
          //“一次赋值,终生不变”
          final int num2 = 20;
          System.out.println(num2); //20
    //        num2 =25;//错误写祛!不能改变!
    //        nun2 = 20; //错误写法!
    
          //正确写法!只要保证有唯——次赋值即可
          final int num3;
          num3 = 30;
          //对于基本类型来说,不可变说的是变量当中的数据不可改变
          //对于引用类型来说,不可变说的是变童当中的地址值不可改变
    

}

### 4. 可以用来修饰一个成员变量
对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变。

1. 由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
2. 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。
3. 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。

public class Person {

private final String name /* =“鹿晗" */;//方法一
public Person(){
    name = "关晓彤";
}

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

public String getName() {
    return name;
}

//public void setName(String name) {
//    this.name = name;
//}

}


文章作者: 刺客世家
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 刺客世家 !
 上一篇
Java笔记--API Java笔记--API
Java笔记–API 应用程序编程接口Application Program Interface 概述API(Application Programming Interface),应用程序编程接口。Java API是—本程序员的字典,是JD
2020-08-17
下一篇 
Java笔记--基础语法 Java笔记--基础语法
java笔记–基础语法 JDK、JRE与JVM第一个Java程序//这是一个程序第三个单词与文件名必须一样 public class HelloWorld { //第二行是万年不变的方法,代表main方法 //程序的入口,做
2020-08-17
  目录