详解 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. 谢谢观看哟~

目录
相关文章
|
26天前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
44 8
|
1月前
|
安全 Java 编译器
Java对象一定分配在堆上吗?
本文探讨了Java对象的内存分配问题,重点介绍了JVM的逃逸分析技术及其优化策略。逃逸分析能判断对象是否会在作用域外被访问,从而决定对象是否需要分配到堆上。文章详细讲解了栈上分配、标量替换和同步消除三种优化策略,并通过示例代码说明了这些技术的应用场景。
Java对象一定分配在堆上吗?
|
26天前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
59 1
|
1月前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
63 17
|
1月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
2月前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
50 17
|
1月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
114 4
|
1月前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
60 2
|
1月前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
51 4
|
1月前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
44 5
下一篇
DataWorks