初始java ( 2 )6000字详解

一:类和对象

Java是一门纯面向对象的语言,在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好

1.1 什么是类和对象

那么什么是类,什么是对象呢?
通俗一点理解就是,类就是一个模板,用来对一个实体进行描述,限定了对象有哪些属性和行为.我们按照这个模板来实例化出许多个对象,
初始java ( 2 )6000字详解_第1张图片
在java中,我们描述一个对象是通过描述这个对象的属性和行为进行描述的,举个例子

当以汽车为例进行描述时,可以将汽车的属性和行为抽象为一个类的属性和方法。

属性(属性描述了汽车的特征):

  • 品牌:描述汽车的品牌,如“奔驰”、“宝马”等。
  • 颜色:描述汽车的外观颜色,如“红色”、“白色”等。
  • 型号:描述汽车的型号,如“SUV”、“跑车”等。

行为(行为描述了汽车能够执行的动作):

  • 加速:描述汽车加速的动作,如“踩油门加速”。
  • 刹车:描述汽车刹车的动作,如“踩刹车减速停车”。
  • 换挡:描述汽车换挡的动作,如“挂1挡、2挡等”。

通过定义汽车类,并在类中定义相应的属性和方法,就能够对汽车进行描述和操作。这样的描述方式能够更清楚地表示汽车对象的特征和能力,使我们可以更好地理解和模拟现实生活中的汽车行为。

因为类是一个模板,它是一个抽象的东西,但是由他产生的对象则是具体的,所以我们经常说实例化一个这个类的对象

1.2 类的定义格式

class ClassName{ 
  field;    // 属性 即 成员变量
  method;    // 行为 即 成员方法
}

class为定义类的关键字,ClassName为类的名字,{ }中为类的主体。
下面通过举例来说明类的定义

当我们描述一个狗狗的时候可以通过狗狗的名字和颜色,以及狗狗狗叫和摇尾巴的行为来进行描述

所以我们可以定义一个这样的狗狗类:

class PetDog {
    // 狗的属性
    public String name;//名字
    public String color;//颜色
  
    // 狗的行为
    public void barks() {
    System.out.println(name + ": 旺旺旺~~~");
    }
    public void wag() {
    System.out.println(name + ": 摇尾巴~~~");
   }
}
  • 属性主要是用来描述类的,属性称之为成员变量。
  • 方法主要说明类具有哪些功能,称为类的成员方法。

1.3局部变量和成员变量

注意成员变量和局部变量是两个不同的概念

成员变量是定义在类中的变量,可以在类的任何方法中使用。它们的作用域是整个类,可以通过对象来访问。通常,成员变量用于存储对象的状态或属性,例如对象的名称、年龄等。成员变量在对象创建时被初始化,并且可以在整个对象的生命周期内被访问和修改。

局部变量是在方法、代码块或构造函数中定义的变量。它们的作用域限定在声明它们的方法、代码块或构造函数的范围内。局部变量只在其定义的范围内可见,并且只能在该范围内访问。局部变量在方法执行时被创建,并在方法结束后被销毁。它们通常用于存储临时数据和方法内部的计算结果。

  • 成员变量可以不用进行初始化
  • 局部变量则必修要进行初始化

以下是类使用过程中的两个注意点:

  1. main方法所在的类一般要使用public修饰
  2. public修饰的类必须要和文件名相同

在Java中,公有类是指被声明为public的类,公有类可以让其他类对这个公有类进行访问。

main方法是Java程序的入口点,是程序执行的起点。Java程序必须包含一个main方法。当程序运行时,Java虚拟机(JVM)会根据这个方法开始执行程序。

main一定要在公有类的主要原因是为了让Java虚拟机能够找到程序的入口,Java虚拟机需要通过反射来调用main方法,而反射只能访问公有方法。如果将main方法定义为非公有的,虚拟机将无法找到并调用该方法,导致程序无法执行。

此外,将main方法置于公有类中还有助于程序的可读性和维护性。公有类作为程序的入口点,可以更方便地理解整个程序的结构和功能。公有类也可以在其他程序中直接被引用,使程序更具可重用性和扩展性。

1.4类的实例化

我们已经有了类了,那么我们该如何通过类来实例化一个对象呢?

class PetDog {
    // 狗的属性
    public String name;//名字
    public String color;//颜色
  
    // 狗的行为
    public void barks() {
    System.out.println(name + ": 旺旺旺~~~");
    }
    public void wag() {
    System.out.println(name + ": 摇尾巴~~~");
   }
}

我们可以通过

 - PetDog dogh = new PetDog();

这行代码来完成对类的示例化,下面我来详细解释一下这段代码的意思:
初始java ( 2 )6000字详解_第2张图片
new是java中的一个关键字,用来创建一个空间,而new PetDog就是创建一个PetDog类型的空间,并且new PetDog会返回创建好空间的地址,而new PetDog后的( )则是传给构造方法的参数

接着dogh是一个引用,我们通过赋值符号 = 将创建好空间的地址赋给了dogh,所以dogh指向了这个空间,PetDog dogh就表示dogh这个引用的类型是PetDog的为什么引用也有类型呢?主要是想说明你这个引用指向的空间应该是PetDog类型的或者子类空间类型的空间(还没有讲到子类,这里简单有个印象即可),并说明dogh能管理的空间只有PetDog类型这么大的空间

下面举一个简单的代码例子来演示一下:

class PetDog {
    // 狗的属性
    public String name;//名字
    public String color;//颜色
  
    // 狗的行为
    public void barks() {
    System.out.println(name + ": 旺旺旺~~~");
    }
    public void wag() {
    System.out.println(name + ": 摇尾巴~~~");
   }
}

public class Main{

	public static void main(String[] args) {
        PetDog dogh = new PetDog();   //通过new实例化对象
    	dogh.name = "阿黄";
    	dogh.color = "黑黄";
    	dogh.barks();
    	dogh.wag();
    
}
}

这段代码的输出结果是:
阿黄: 旺旺旺~~~
阿黄: 摇尾巴~~~

  • 在java中我们使用 . 来访问对象中的属性和方法.
  • 并且同一个类可以创建多个实例.

1.5 this引用

首先我们来思考一下为什么要有this引用,下面通过一个代码来引出:

public class Person {
    String name;
    int age;

    public void setPerson(String n, int a) {
        name = n;
        age = a;
    }

    public void printDetails() {
        System.out.println("姓名:" + this.name);
        System.out.println("年龄:" + this.age);
    }

    public static void main(String[] args) {
       Person person = new Person();
 	   person.setPerson(张三,20;
 	   person.printDetails();
    }
}

再这段代码中,我们先实例化了一个Person对象,接着通过person这个对象中的setPerson方法对name和age进行了实例化,接着通过person这个对象中的printDetails方法对信息进行打印,运行结果如下:
姓名:张三
年龄:20

但是万一我们不小心将setPerson方法错误的写成了

 public void setPerson(String name, int age) {
        name = name;
        age = age;
    }

这样我们就分不清楚我们传入的name是哪个了,并且根据局部优先的原则,程序会将name = name 被解析成了,将成员变量name赋值给形参变量name,这和我们的本意相反

那么我们该如何避免这种情况呢?答案是通过this引用

this引用有三个很重要的作用:

  • 通过this区分局部变量和成员变量

我们可以通过this.name来告诉编译器,这个name是成员变量中的name,而不是局部变量的name

  • 在类中通过this.方法名()来调用本类的成员方法

我们可以在Person类中通过this.printDetails()来调用printDetails()这个方法

  • 通过this()来在构造方法中调用其他构造方法

我们可以通过this()来在构造方法中调用其他构造方法,并且这一行代码应该在第一行

所以我们可以对上述的代码进行改进

public class Person {
    String name;
    int age;

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

    public void printDetails() {
        System.out.println("姓名:" + this.name);
        System.out.println("年龄:" + this.age);
    }

    public static void main(String[] args) {
       Person person = new Person();
 	   person.setPerson(张三,20;
 	   person.printDetails();
    }
}

this.name = name;表示将局部变量name赋值给成员变量name,这样就可以避免了冲突,而且方便我们更加直观的去理解代码

1.6 构造方法

public class Person {
    String name;
    int age;

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

    public void printDetails() {
        System.out.println("姓名:" + this.name);
        System.out.println("年龄:" + this.age);
    }

    public static void main(String[] args) {
       Person person = new Person();
 	   person.setPerson(张三,20;
 	   person.printDetails();
    }
}

在这段代码中,我们每创建一个对象都要通过setPerson这个方法来对对象进行初始化,在java中,创建对象是一个很频繁的事情,所以我们没创建一个对象就要去调用一次setPerson方法是不是有点太麻烦了?

所以java给我们提供了一个方法,名为构造方法,构造方法每创建一次对象,就会为这个对象调用一次构造方法,所以我们就可以通过构造方法来完成对对象的初始化

所以上述代码我们可以改成:

public class Person {
    String name;
    int age;

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

    public void printDetails() {
        System.out.println("姓名:" + this.name);
        System.out.println("年龄:" + this.age);
    }

    public static void main(String[] args) {
       Person person = new Person();
 	   person.setPerson(张三,20;
 	   person.printDetails();
    }
}

构造方法的特性:

  1. 构造方法的名字必须与类名相同
  2. 没有返回值类型,设置为void也不行
  3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
  4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)

下面我来对这些特性进行说明:

构造方法的名字为什么要和类名相同?

  1. 方便代码阅读和理解,如果名字不一致的话,会让人感到困惑,而如果名字一致的话,就很容易让人明白这是构造方法,用来帮助对象的初始化
  2. 方便编译器确定该类的构造方法是哪一个,避免了由构造方法名称不明确带来的编译错误

为什么构造方法没有返回值类型,void也不可以?

  1. 因为构造方法的主要目的就是为了帮助对象完成初始化,我们并不需要返回值,并且通过不写返回值,能够更好的告诉我们这个方法是构造方法,用于帮助对象的初始化

注意:当一个类实例化了一个对象,那么就一定要调用一次构造方法,如果用户没有定义构造方法,那么系统会默认生成一份没有参数的构造方法供我们使用,但是如果我们写了任意一个构造方法,那么系统就不会帮我们生成这个无参的构造方法了

构造方法在实例化对象的时候一定要被调用,如果没有调用则会报错

PetDog dogh = new PetDog(张三,20);我们可以在实例化对象的时候通过()来将参数传递给构造方法,记得顺序和类型要对应上哦

在构造方法中,我们可以通过this()来调用其他的构造方法,其中this中的括号要放入对应的参数比如:this (1900,1,1);且this (1900,1,1);必须是第一条语句

二:成员变量的默认初始化

为什么局部变量在使用的时候必须要初始化,而成员变量可以不用呢?
要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:

  1. 检测对象对应的类是否加载了,如果没有加载则加载

  2. 为对象分配内存空间

  3. 处理并发安全问题
    比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突

  4. 初始化所分配的空间
    即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:
    初始java ( 2 )6000字详解_第3张图片

  5. 设置对象头信息(关于对象内存模型后面会介绍)

  6. 调用构造方法,给对象中各个成员赋值

所以当我们实例化一个对象之后,就已经给成员变量赋值了,那些值都是0的变式,当然我们也可以在类中对成员变量进行赋值比如:

public class Date {
  public int year = 1900;
  public int month = 1;
  public int day = 1;
}

你可能感兴趣的:(java,java)