详解 Java 的对象与类(一)

简介: 详解 Java 的对象与类(一)

入门对象和类



什么是类?


这里所说的类其实就是自定义的类型。


举个例子:在高中,高一可以认为是一个类,他们属于新生;高二可以认为是一个类,他们通过文理分科分到一个新的班级;高三也可以认为是一个类,他们即将参加高考。创建一个类,就是因为普通类型满足不了我们的需求,我们想好一个事物的特点,来个性化 / 自定义一个种类,再通过当前类的属性来完成预期的目标。


什么是对象?


下面会介绍到。


1. 成员变量和成员方法



在程序清单1中,我们创建一个类 Person


name,age 被称为 字段/属性/成员变量(类的内部,方法的外部)
eat(),sleep() 被称为成员方法,表示类中的某种行为


程序清单1:


class Person{
    public String name;
    public int age;
    public void eat(){
        System.out.println(name+" 正在吃饭");
    }
    public void sleep(){
        System.out.println(name+" 正在睡觉");
    }
}
public class Test {
    public static void main(String[] args) {
        Person person = new Person();
    }
}


2. 由类构造对象的过程称为创建类的实例



也就是说:对象是通过类实例化出来的


new Person( ) 这个表达式构造了一个新的对象,person 就是被类 Person 创建的一个对象变量。


Person 在 Java 中表示的是引用类型,它在意义上相当于 int,因为 int 是整型。


person 是通过引用类型定义的,所以 person 就是引用变量,也可以把 person 叫做对象的引用。


Person person = new Person();
int a = 10;


类 Person 相当于一个模板,它可以实例化多个对象


public class Test {
    public static void main(String[] args) {
        Person person1 = new Person();
        Person person2 = new Person();
        Person person3 = new Person();
        Person person4 = new Person();
        Person person5 = new Person();
    }
}


3. 访问类中成员变量



访问类中成员变量的格式:[ 对象变量 ] + . + [ 字段 ] 
如:person.name


(1)演示1


程序清单2:


class Person{
    public String name;
    public int age;
    boolean result;
}
public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);
        System.out.println(person.age);
        System.out.println(person.result);
    }
}


输出结果:


f5d5f07049604862a29d974cf0a3922c.png


在程序清单2中,字段/成员变量 如果未被初始化,那么 int 类型默认为0,String 类型默认为null,boolean 类型默认为 false.


(2)演示2


程序清单3:


class Person{
    public String name;
    public int age;
}
public class Test {
    public static void main(String[] args) {
        Person person1 = new Person();
        Person person2 = new Person();
        Person person3 = new Person();
        person2.name = "吉姆";
        person2.age = 17;
        person3.name = "露丝";
        person3.age = 21;
        System.out.println(person1.name);
        System.out.println(person1.age);
        System.out.println("-----------------");
        System.out.println(person2.name);
        System.out.println(person2.age);
        System.out.println("-----------------");
        System.out.println(person3.name);
        System.out.println(person3.age);
    }
}


输出结果:我们可以看到,创建一个对象,那么赋值给类的时候,这些值就属于对象了。


e4e36ad59da34188a5874c089a7fdb54.png


在程序清单3中,类是对象的模板。


接下来我举个例子:刚开始,我没有创建对象的时候,这块模板是崭新的,什么颜色也没有。而当我新创建了一个对象的时候,我就拿到了这个崭新的模板,此时我可以给这个模板上色,让它变成蓝色。然而,我又可以创建另一个对象,此时我又拿到了一块崭新的模板,我可以给这个模板上色,让它变成绿色…当我不给这块模板上色的时候,它依然是那块崭新的模板。没错,就是这么回事儿!


简而言之,只要我通过类 Person 创建了一个对象,那么我就拿到了一个初始类中的所有字段,我就可以对这个类进行改造,而 person1,person2,person3 两两类之间没有任何关联。


fa4b7c8d37b84bea9ecd107b99080423.png


4. 访问类中的成员方法



访问类中的方法的格式: [ 对象变量 ] + . + [ 方法 ]
如: person1.eat( )


程序清单4:


class Person{
    public String name;
    public void eat(){
        System.out.println(name+" 正在吃饭");
    }
    public void sleep(){
        System.out.println(name+" 正在睡觉");
    }
}
public class Test {
    public static void main(String[] args) {
        Person person1 = new Person();
        person1.name = "吉姆";
        person1.eat();
        Person person2 = new Person();
        person2.name = "露丝";
        person2.sleep();
    }
}


84d48d982f0547ad96738ef7ea7f2451.png


5. 静态的成员



静态成员被 static 关键字修饰,在介绍静态成员之前,读者请看一个例子


程序清单5:


class Person{
    public int count;
    public static int size;
}
public class Test {
    public static void main(String[] args) {
        Person person1 = new Person();
        Person person2 = new Person();
        person1.count++; //1
        System.out.println(person1.count);
        person2.count++; //1
        System.out.println(person2.count);
        System.out.println("---------------");
        person1.size++; //1
        System.out.println(person1.size);
        person2.size++; //2
        System.out.println(person2.size);
    }
}


输出结果


932fac0133a7478e8efd54502e70a3a6.png


我相信通过上面的介绍,对于 person1.count++ 和 person2.count++,大家已经不陌生了,因为 count 是通过对象变量进行操作的,person1 和 person2 是两个不同的对象变量,也就是两个不同对象操作的结果,所以各自为1,互不影响。


而通过关键字 static 修饰的 size 就不同了,因为 static 修饰的成员变量被放置在方法区,只有一份,所以 person1.size++ 和 person2.size++ 其实是对同一份的 size 进行操作。


那么我们就可以通过类直接访问静态成员变量了!


访问格式:[ 类名 ] . [ 静态成员变量 ]


程序清单6:


class Person{
    public static int size;
}
public class Test {
    public static void main(String[] args) {
        Person.size++; //1
        System.out.println(Person.size);
        Person.size++; //2
        System.out.println(Person.size);
    }
}


程序清单7:


class Person{
    public static String name1;
    public static void run(){
        System.out.println(name1 + " 正在跑步");
    }
}
public class Test {
    public static void main(String[] args) {
        Person.name1 = "杰克";
        Person.run();
    }
}


输出结果:


d09a431ff4394c008813bc784f4e19d3.png


结论:


① 被 static 关键字修饰的变量和方法由类直接控制,被所有类共享。

② 被 static 关键字修饰的变量不属于对象,或者说不依赖于对象,所以它也被叫做类变量。

③ 被 static 关键字修饰的方法不属于对象,或者说不依赖于对象,所以它也被叫做类方法。


6. 静态与非静态的关系



在程序清单8中,其中有两行代码会被编译器报错,我已经通过注释标明出来了。


我想说明的问题是:不论在静态成员方法中,还是在非静态成员方法中,我们都无法定义静态的变量,因为我们要时刻记住,关键字 static 修饰的变量永远是属于类的,不属于某个方法,我们只能通过类来访问和操作!


程序清单8:


class Person{
    public static String name1;
    public void swim(){
        static int a = 10; //error
        System.out.println(name1 + " 正在游泳");
    }
    public static void run(){
        static int b = 10; //error
        System.out.println(name1 + " 正在跑步");
    }
}


同样地,关于静态的方法也有讲究,非静态的方法可以调用静态的方法,而静态的方法不能调用非静态的方法 ,因为静态的方法不依赖对象,非静态的方法依赖对象。


程序清单9:


class Person{
    public static String name1;
    public void swim(){
        run();
        System.out.println(name1 + " 正在游泳");
    }
    public void eat(){
        swim();
        System.out.println(name1 + " 正在吃饭");
    }
    public static void run(){
        swim(); //error
        System.out.println(name1 + " 正在跑步");
    }
    public static void sleep(){
        run(); 
        System.out.println(name1 + " 正在睡觉");
    }
}


拓展一下,如果有的人性格就比较犟,就是要用静态的方法调用非静态的方法,那么我们就在调用之前,在静态的方法中创建一个对象就行了,举个例子:通过对象变量 person 访问 swim( ) 即可,但是很少有人这么做,因为无非就是加或不加 static 的事情,我只是想更深刻地理解这些知识,所以展示的代码如下:


程序清单10:


class Person{
    public static String name1;
    public void swim(){
        run();
        System.out.println(name1 + " 正在游泳");
    }    
    public static void run(){
        Person person = new Person();
        person.swim(); //right
        System.out.println(name1 + " 正在跑步");
    }
}


7. 说明两种情况



① person 这个引用不指向任何的对象


Person person = null;


② person2 这个引用指向 person1 这个引用指向的对象

或者说:person1 和 person2 引用了相同的对象。(对象只有一个)


Person person1 = new Person();
Person person2 = person1;


程序清单11:


class Person{
    public int age;
}
public class Test {
    public static void main(String[] args) {
        Person person = null;
        Person person1 = new Person();
        Person person2 = person1;
        person1.age = 10;
        System.out.println(person2.age); //输出10     
    }
}


8. 介绍 toString 方法



① 程序清单12:


class Person{
    public String name;
    public int age;
}
public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "吉姆";
        person.age = 18;
        System.out.println(person);
    }
}


程序清单12 的输出结果:demo3 表示一个包,Person 表示包下的一个类,@… 表示地址


我们打印的是对象变量 person,即表示引用变量指向的地址。


d09a431ff4394c008813bc784f4e19d3.png


程序清单13 对程序清单12 做出了一些改变


程序清单13:


class Person{
    public String name;
    public int age;
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "吉姆";
        person.age = 18;
        System.out.println(person);
    }
}


1b1e1b8645424d2ca8fe20f43e943a0a.png


在程序清单13中,我们使用了 toString 方法:


@Override 表示重写,public String toString( ) 这个方法是通过 IDEA 编译器自动生成的,它可以返回表示对象值的字符串,这样做的目的是:程序员清楚地知道对象的状态,同时也提升了其他人的代码可读性。


9. 构造方法



关于构造方法的一些说明:


(1)构造方法的方法名和类名是相同的

(2)构造方法比较特殊,没有返回值

(3)构造方法之间构成重载


那么如何使用创建的构造方法呢?在通过关键字 new 创建对象的时候,我们就可以输入构造方法中对应的参数了。详见程序清单14.


程序清单14:


class Person{
    public String name;
    public int age;
    public Person(){
        System.out.println("调用不带参数的构造方法");
    }
    public Person(String name){
        this.name = name;
        System.out.println("调用带有一个参数的构造方法");
    }
    public Person(String name,int age){
        this.name = name;
        this.age = age;
        System.out.println("调用带有两个参数的构造方法");
    }
}
public class Test {
    public static void main(String[] args) {
        Person person1 = new Person();
        Person person2 = new Person("罗恩");
        Person person3 = new Person("杰克",21);
    }
}


输出结果:


28a0c9a0df8b4c359d8e2d13f1e97a08.png


在程序清单15 中,在类 Person 中, 如果你没有实现任何的构造方法时,编译器会帮我们默认生成一个不带参数的构造方法,也就是说,一个类至少有一个构造方法,即使你没有写!


程序清单15:


class Person{
    public String name;
    public int age;
}
public class Test {
    public static void main(String[] args) {
        Person person1 = new Person();
    }
}


编译器自动生成的构造方法就是如下代码:


public Person(){
}


10. 代码块



(1)实例代码块


{
}


(2)静态代码块


static
{
}


让我们来看看以下的几个程序清单:


程序清单16:


class Student{
    public String name;
    public int age;
    public static double grade;
    //实例代码块
    {
        name = "李明";
        age = 17;
    }
    //静态代码块
    static
    {
        grade = 88.5;
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student();
        System.out.println(student1.name);
        System.out.println(student1.age);
        System.out.println(Student.grade);
    }
}



输出结果:


97411b2fe613433cbbacb66b734bd5f7.png


程序清单17:


class Student{
    public Student(){
        System.out.println("不带参数的代码块");
    }
    {
        System.out.println("实例代码块");
    }
    static
    {
        System.out.println("静态代码块");
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student();
        System.out.println("----------------");
        Student student2 = new Student();
    }
}


输出结果:


eeb34b3d489c414bbdec7bd47d19f5fe.png


程序清单18:


class Student{
    public static int count;
    public Student(){
        System.out.println("不带参数的代码块");
    }
    {
        System.out.println("实例代码块");
    }
    static
    {
        count++;
        System.out.println("静态代码块");
    }
}
public class Test {
    public static void main(String[] args) {
        System.out.println(Student.count);
    }
}


输出结果:


bb4b96b32b614637826b25e9adc874ae.png


程序清单19:


class Person{
    public static int count;
    static
    {
        count = 10;
    }
}
public class Test {
    public static void main(String[] args) {
        System.out.println(Person.count); //10
    }
}


程序清单20:


class Person{
    static
    {
        count = 10;
    }
    public static int count;
}
public class Test {
    public static void main(String[] args) {
        System.out.println(Person.count); //10
    }
}


程序清单21:


class Person{
    static
    {
        count = 10;
    }
    public static int count = 99;
}
public class Test {
    public static void main(String[] args) {
        System.out.println(Person.count); //99
    }
}


总结:


① 实例代码块被用来初始化非静态成员变量的值,静态代码块被用来初始化静态成员变量的值。

② 静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行。

③ 静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。

④ 静态代码块中的成员变量被赋值,最终输出的结果和顺序有关。


11. 匿名对象



让我们来看看程序清单22,我们就能明白匿名对象的含义了。


匿名对象表示没有引用的对象,new Person( ) 只能被用一次,而且在下一次这么用的时候,不会衔接上一个变量值,这就相当于:一个对象只被用了一次,之后就恢复到原始状态了。


程序清单22:


class Person{
    public String name;
    public void swim(){
        System.out.println(name + " 正在游泳");
    }
    public  void run(){
        System.out.println(name + " 正在跑步");
    }
}
public class Test {
    public static void main(String[] args) {
        new Person().name = "Jack";
        System.out.println(new Person().name);
        new Person().swim();
        new Person().run();
    }
}


d10523b1fd054df7b3f8ef132a8ffb1f.png


13c564346ca4441fbe5fdeab3c7805b8.jpg


Over. 谢谢观看哟~

目录
相关文章
|
1天前
|
Java 开发者
在Java中,接口和超类在多态性中扮演着重要的角色
Java中的接口和超类支持多态性,接口作为规范,允许多继承和回调机制;超类提供基类,实现代码重用和方法重写,两者共同促进代码的灵活性和可维护性。
23 10
|
1天前
|
Java
Java并发Futures和Callables类
Java程序`TestThread`演示了如何在多线程环境中使用`Futures`和`Callables`。它创建了一个单线程`ExecutorService`,然后提交两个`FactorialService`任务,分别计算10和20的阶乘。每个任务返回一个`Future`对象,通过`get`方法获取结果,该方法会阻塞直到计算完成。计算过程中模拟延迟以展示异步执行。最终,打印出10!和20!的结果。
|
6天前
|
SQL Java 数据库连接
15:MyBatis对象关系与映射结构-Java Spring
15:MyBatis对象关系与映射结构-Java Spring
27 4
|
6天前
|
网络协议 Java
Java中如何使用Socket类检测端口是否存在
Java中如何使用Socket类检测端口是否存在
24 4
|
6天前
|
存储 缓存 前端开发
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
23 3
|
6天前
|
存储 Java
Java的`java.io`包包含多种输入输出类
Java的`java.io`包包含多种输入输出类。此示例展示如何使用`FileInputStream`从`input.txt`读取数据。首先创建`FileInputStream`对象,接着分配一个`byte`数组存储流中的数据。通过`read()`方法读取数据,然后将字节数组转换为字符串打印。最后关闭输入流释放资源。`InputStream`是抽象类,此处使用其子类`FileInputStream`。其他子类如`ByteArrayInputStream`、`ObjectInputStream`和`BufferedInputStream`各有特定用途。
15 1
|
8天前
|
Java 开发者
Java中三种Set的实现类的用法和区别
Java中三种Set的实现类的用法和区别
|
8天前
|
消息中间件 安全 Java
在Spring Bean中,如何通过Java配置类定义Bean?
【4月更文挑战第30天】在Spring Bean中,如何通过Java配置类定义Bean?
18 1
|
9天前
|
Java 编译器
【Java探索之旅】解密构造方法 对象初始化的关键一步
【Java探索之旅】解密构造方法 对象初始化的关键一步
15 1
|
9天前
|
Java
Java对象和类研究
Java对象和类研究
8 0