Bootstrap

【Java SE】类和对象(全网最细详解)

 🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!

欢迎志同道合的朋友一起加油喔🤺🤺🤺

目录

前言

一、面向对象的初步认知

1.什么是面向对象

2.面向对象和面向过程的区别

二、类和对象的基本概念

三、类和对象的定义和使用

1、类的创建

2.对象的使用

3.成员变量与局部变量的区别 

四.this关键字

五.构造方法

1.构造方法怎么定义,语法是什么?

2.构造方法的注意事项

3.实例变量在类加载是初始化吗?实例变量在什么时候初始化?

4.构造方法有几种,各自的作用是什么?

六.什么是封装?

七.static关键字

八.final关键字

9.代码块

总结



前言

什么是对象?

万物皆对象,客观存在的事物都是对象,大到名胜古迹,小到剪刀、钟表、信封等,所有的一切都围绕对象进行,找对象、建对象,用对象等.在了解类和对象之前我们先来了解一下java中面向对象与c语言的面向过程有什么区别吧.学完这一节后还没有对象那就赶紧new一个吧!


一、面向对象的初步认知

1.什么是面向对象

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

2.面向对象和面向过程的区别

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

例如:

可以拿生活中的实例来理解面向过程与面向对象,例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用不同的方法来实现。

如果是面向对象的设计思想来解决问题。面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。

可以明显地看出,面向对象是以功能来划分问题,而不是步骤。同样是绘制棋局,这样的行为在面向过程的设计中分散在了多个步骤中,很可能出现不同的绘制版本,因为通常设计人员会考虑到实际情况进行各种各样的简化。而面向对象的设计中,绘图只可能在棋盘对象中出现,从而保证了绘图的统一。


二、类和对象的基本概念

类:把具有相同属性和行为的一类对象抽象为类。类是抽象概念,如人类、犬类等,无法具体到每个实体。

对象:某个类的一个实体,当有了对象后,这些属性便有了属性值,行为也就有了相应的意义。

类是描述某一对象的统称,对象是这个类的一个实例而已。有类之后就能根据这个类来产生具体的对象。一类对象所具备的共同属性和行为(方法)都在类中定义。


三、类和对象的定义和使用

1、类的创建

class 类名称 {                   //用class关键字定义类
 
属性/字段/成员变量/ 实例变量;     //定义在类中方法外
 
行为/成员方法;
 
}

在java中,类名定义没有什么规则,只要不是关键字都不会报错,但是一个良好的编程习惯定义类名需要注意一些细节:

  1. 类名的第一个字母大写

  2. 类名尽量使用字母

  3. 类名要见名知意

  4. 类名不要使用关键字

属性用于定义该类或该类对象包含的数据或者说静态特征。属性作用范围是整个类中。
属性定义格式:
[修饰符]  属性类型  属性名 = [默认值] ;

(2)方法
方法用于定义该类或该类实例的行为特征和功能实现。方法是类和对象行为特征的抽象。
方法定义格式:
[修饰符]  方法返回值类型  方法名(形参列表) {
        // n条语句
}

void代表没有返回值;方法的作用:重用代码,封装功能,便于修改

代码展示如下:

public class Person {
    //属性/字段/成员变量
    int age ;//年龄
    String name;//姓名
    double height;//身高
    double weight;//体重
    //动词---》方法
    //吃饭
    public void eat(){
        int num = 10;//局部变量:放在方法中
        System.out.println("我喜欢吃饭");
    }
    //睡觉:
    public void sleep(String address){          //对象调用这个方法的时候会传一个地址过来
        System.out.println("我在"+address+"睡觉");
    }
    //自我介绍:
    public String introduce(){
        return "我的名字是:"+name+",我的年龄是:"+age+",我的身高是:"+height+",我的体重是:"+weight;
    }
}

2.对象的使用

1.创建对象(类的实例化)
格式:类名 对象名 = new 类名();                          //用new关键字实例化一个对象,只要使用new关键字就会在堆里面开辟一块新的空间
范例:Phone phone1 =new Phone();                    //一个类可以实例化多个对象
2.使用对象  
#2.1使用成员变量
格式: 对象名称.变量                                            //通过对象调用属性可以输出属性或者给属性赋值
范例:    phone1 .brand="xiaomi";
#2.2使用成员方法 
格式: 对象名称.方法名                                        //通过对象调用方法可以输出方法的内容
范例:phone1.call();

 代码展示如下:

//测试类
public class Test {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //创建一个人类的具体的对象/实例:
        //创建一个对象,对象的名字叫:小盈盈
        //Person 属于 引用数据类型
        //第一次加载类的时候,会进行类的加载,初始化创建对象的时候,对象的属性没有给赋值,有默认的初始化的值。
        Person zs = new Person();
        zs.name = "小盈盈";
        zs.age = 19;
        zs.height = 180.4;
        zs.weight = 170.4;
        //再创建一个对象:
        //再次创建类的时候,就不会进行类的加载了,类的加载只在第一次需要的时候加载一次
        Person ls = new Person();
        ls.name = "小阿宝";
        ls.age = 18;
        ls.height = 170.6;
        ls.weight = 160.5;
        //对属性值进行读取:
        System.out.println(zs.name);
        System.out.println(ls.age);
        //对方法进行操作:
        //不同的对象,属性有自己的特有的值,但是方法都是调用类中通用的方法。
        //属性:各个对象的属性是独立的,
        //方法:各个对象的方法是共享的。
        zs.eat();
        ls.eat();
        zs.sleep("教室");
        /*String str = zs.introduce();
        System.out.println(str);*/
        System.out.println(zs.introduce());
    }
}


3.成员变量与局部变量的区别 

成员变量:类中的方法外的变量 就是成员变量

局部变量:方法中的变量 就是局部变量

 成员变量的默认值:

 注意:成员变量有默认的初始化值,不建议显示初始化,后续使用的时候再赋值即可;

         而局部变量一定要在使用前进行赋值,不然使用的时候报错!

四.this关键字

this:代表所在的类对象的引用;        

方法被哪个对象调用,this就代表哪个对象

this关键字可以用来访问本类的属性、方法、构造方法                                                                         // 阿巴巴巴开发手册指明习惯使用this关键字

this关键字的用法:

(1)this可以修饰属性(用于区别成员变量和局部变量):
总结:当属性名字和形参发生重名的时候,或者 属性名字和局部变量重名的时候,都会发生就近原则(局部变量优先),所以如果我要是直接使用变量名字的话就指的是离的近的那个形参或者局部变量,这时候如果我想要表示属性的话,在前面要加上:this.修饰

如果不发生重名问题的话,实际上你要是访问属性也可以省略this.

(2)this修饰方法:
总结:在同一个类中,方法可以互相调用,this.可以省略不写。
(3)this可以修饰构造方法:
总结:同一个类中的构造方法可以相互用this调用,调用构造方法的语法:  this(参数列表)                  //this调用构造方法只能在构造方法里面使用
注意:this修饰构造方法必须放在第一行   (原因是为了保证父类对象初始化的唯一性)

 (4)   this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法
对象的引用传递给该成员方法,this负责来接收
在代码层面来简单演示--->注意:下图右侧中的Date类也是可以通过编译的


五.构造方法

1.构造方法怎么定义,语法是什么?

[修饰符列表]   类名(形式参数列表){

               构造方法体;                                              //通常在构造方法体当中给属性赋值,完成属性的初始化。

}  

注意:

  1. 第一:修饰符列表目前统一写:public。千万不要写public static。
  2. 第二:构造方法名和类名必须一致
  3. 第三:构造方法不需要指定返回值类型,也不能写void,写上void表示普通方法,就不是构造方法了。

普通方法的语法结构是?
    [修饰符列表]  返回值类型  方法名(形式参数列表){
                          方法体;
    }

2.构造方法的注意事项

1.如果没有定义构造方法,系统将给出一个默认的无参构造方法

2.如果定义了构造方法,系统将不再提供默认的构造方法             

方法重载:构造方法名称相同但是参数列表不同 这就是重载。

注意:如果自定义了带参数的构造方法,还要使用无参数构造方法,就必须要写一个无参构造方法

建议:无论是否使用,都要保持无参构造方法的存在

3,每创建一次对象,就会调用一次构造方法

3.实例变量在类加载是初始化吗?实例变量在什么时候初始化?

不是,实例变量(成员变量/属性)是在构造方法执行的过程完成初始化的,完成赋值的.

Person p = new Person();

创建一个对象都在内存中做了什么事情?

1:先将硬盘上指定位置的Person.class文件加载进内存。 (只加载一次)

2:执行main方法时,在栈内存中开辟了main方法的空间(压栈-进栈),然后在main方法的栈区分配了一个变量p。

3:在堆内存中开辟一个实体空间,分配了一个内存首地址值。new

4:在该实体空间中进行属性的空间分配,并进行了默认初始化。

5:对空间中的属性进行显示初始化。

6:进行对象的构造代码块初始化。

7:调用该对象对应的构造方法,进行构造方法初始化。()

8:将首地址赋值给p ,p变量就引用了该对象。(指向了该对象)

注意:在调用构造方法前,我们会先执行父类的静态,子类的静态,并且静态内容之后执行一次,然后再执行父类的实例,父类的构造方法,子类的实例,子类的构造方法.

这里的实例包括实例变量和实例代码块(构造代码块/非静态代码块).   

(这一块听不懂的后续看完继承回来就明白了,算是一个小小的拓展,后续继承和多态还会再讲)

4.构造方法有几种,各自的作用是什么?

无参构造方法:初始化对象时,成员变量的数据均采用默认值.

有参构造方法:在初始化对象的时候,同时可以为对象进行赋值.

它们本质上都是在创建对象的时候,由虚拟机自动调用,给成员变量进行初始化的,并且初始化动作只会执行一次!


六.什么是封装?

面向对象的三个基本特征(oop)之一:(封装、继承、多态 )

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

封装的规则:

1.将类的某些信息隐藏在类的内部,不允许外部的程序直接访问;

2.通过该类提供的方法来实现对隐藏信息的操作和访问

封装的实现:

1.修改属性私有(设为private)

2.创建get/set方法(方法用public修饰用于属性的读写)

3.在get/set方法中加入属性控制语句(对属性的合法性进行判断)

private int age;//修饰符私有的,访问权限最低,只有在本类中的访问有效             

(注意:私有仅仅是封装的一种体现形式而已.)

私有的成员:其他类不能直接创建对象访问,所以只有通过本类对外提供具体的访问方式来完成对私有的访问,可以通过对外提供函数的形式对其进行访问。

好处:可以在函数中加入逻辑判断等操作,对数据进行判断等操作。

总结:开发时,记住,属性是用于存储数据的,直接被访问,容易出现安全隐患,所以,类中的属性通常被私有化,并对外提供公共的访问方法。

set方法:用于给成员变量赋值,方法用public修饰.

访问格式:对象.setXXX(要赋值的参数)

get方法:对外提供成员变量的值,方法用public修饰.

访问格式:对象.getXXX()

通过下面一段代码感受封装:

public class Girl {//女孩
    //属性:
    private int age;
    //读取年龄:
    public int getAge(){
        return age;
    }
    //设置年龄:
    public void setAge(int age){
        if(age >= 30 ){
            this.age = 18;     //当女孩的年龄为30时我们会通过限制条件自动改回18
        }else{
            this.age = age;        
        }
    }
}
public class Test {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //创建一个Girl类的对象:
        Girl g = new Girl();
        /*g.age = 33;            //由于进行了封装,直接访问会报错
        System.out.println(g.age);*/
        //设置年龄:
        g.setAge(31);          
        //获取年龄:
        System.out.println(g.getAge());
    }
}


七.static关键字

static关键字,是一个修饰符,用于修饰成员(成员变量和成员方法)。

特点:

1,想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。

2,被静态修饰的成员(成员变量和成员方法),可以直接被类名所调用。也就是说,静态的成员多了一种调用方式。类名.静态成员(推荐)

3,静态随着类的加载而加载。而且优先于对象存在。

弊端:

1,有些数据是对象特有的数据,是不可以被静态修饰的。因为那样的话,特有数据会变成对象的共享数据。       这样对事物的描述就出了问题。所以,在定义静态时,必须要明确,这个数据是否是被对象所共享的。

2,静态方法只能访问静态成员,不可以访问非静态成员

因为静态方法加载时,优先于对象存在,所以没有办法访问对象中的成员。

3,静态方法中不能使用this,super关键字。

因为this代表对象,而静态在类的加载时就存在了,有可能没有对象,所以this无法使用。

4,静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用(可以看上面this参数的解释)

什么时候定义静态成员呢?或者说:定义成员时,到底需不需要被静态修饰呢?

成员分两种:

1,成员变量。数据共享时静态化

该成员变量的数据是否是所有对象都一样:

如果是,那么该变量需要被静态修饰,因为是共享的数据。

如果不是,那么就说这是对象的特有数据,要存储到对象中。

2,成员方法。方法中没有调用特有数据时就定义成静态

    如果判断成员方法是否需要被静态修饰呢?

    只要参考,该方法内是否访问了对象中的特有数据(指的是非静态成员),

    如果有访问特有数据,那方法不能被静态修饰(因为静态方法不能访问非静态成员)。

    如果没有访问过特有数据,那么这个方法需要被静态修饰。

成员变量和静态变量的区别:

1,成员变量所属于对象。所以也称为实例变量。

静态变量所属于类。所以也称为类变量。

2,成员变量存在于堆内存中。

静态变量存在于方法区中。

3,成员变量随着对象创建而存在。随着对象被回收而消失。

静态变量随着类的加载而存在。随着类的消失而消失。

4,成员变量只能被对象所调用 。

静态变量可以被对象调用,也可以被类名调用。

所以,成员变量可以称为对象的特有数据,静态变量称为对象的共享数据。


八.final关键字

1:这个关键字一个修饰符,可以修饰类,方法,变量。

2:被final修饰的类是一个最终类,不可以被继承。

3:被final修饰的方法是一个最终方法,不可以被覆盖。

4:被final修饰的变量是一个常量,只能赋值一次。

5:  final修饰的局部变量

基本数据类型:final修饰的基本数据类型的值不能够被修改的;

引用数据类型:final修饰的引用数据类型引用类型地址不能够发生变化的,但是引用类型的

地址里面的成员属性值是可以发生变化的。

    其实这样的原因的就是给一些固定的数据起个阅读性较强的名称。

    不加final修饰不是也可以使用吗?那么这个值是一个变量,是可以更改的。加了final,程序更为严谨。常量名称定义时,有规范,所有字母都大写,如果由多个单词组成,中间用 _ 连接。

    //final修饰的属性  一定要给初始值

    //1、在定义时候直接赋值

    //2、用构造方法赋值    必须每个构造方法中都有赋值语句(直接赋值或者调用其他构造方法赋值)

下面代码展示final修饰属性一点要赋初值的细节:

	public class Cat {
      //final int NUM =20;      //直接定义的时候赋值 
		final int NUM;
		public Cat(int NUM){
	      //this.NUM=NUM;      //创建对象的时候调用构造方法通过传参直接赋值  
			this();            //调用其他构造方法赋值
		}
		public Cat(){
			NUM=10;
		}
	}

9.代码块

普通代码块:定义在方法中的代码块.

构造代码块:定义在类中的代码块(不加修饰符)。也叫:实例代码块或者非静态代码块.

构造代码块一般用于初始化实例成员变量。

静态代码块:使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。

注意事项:

静态代码块不管生成多少个对象,其只会执行一次
静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)
实例代码块只有在创建对象时才会执行

总结:
(1)代码块执行顺序:
先执行静态块,只在类加载的时候执行一次(new多个对象也只会执行一次),所以一般以后实战写项目:创建工厂,数据库的初始化信息都放入静态代码块。
一般用于执行一些全局性的初始化操作。

再执行构造代码块(不常用)
再执行构造方法,
再执行方法中的普通代码块。

(2)构造代码块和构造方法有什么区别?

构造代码块:是给所有的对象进行初始化,也就是说,所有的对象都会调用一个代码块。只要对象一建立。就会调用这个代码块。

构造方法:是给与之对应的对象进行初始化。它具有针对性。

下面代码展示了所有代码块执行的顺序:

public class Test {
    //属性
    int a;
    static int sa;     //sa默认值为0
    //方法
    public void a(){
        System.out.println("-----a");
        {
            //普通块限制了局部变量的作用范围
            System.out.println("这是普通代码块");
            System.out.println("----000000");
            int num = 10;
            System.out.println(num);
        }

    }
    public static void b(){
        System.out.println("------b");
    }
    //构造块
    {
        System.out.println("------这是构造代码块");
    }
    //静态块
    static{
        System.out.println("-----这是静态代码块");
        //在静态块中只能有:静态属性,静态方法
        System.out.println(sa);
        b();
    }
    //构造方法
    public Test(){
        System.out.println("这是空参构造方法");
    }
    public Test(int a){
        this.a = a;
    }
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        Test t = new Test();
        t.a();
        Test t2 = new Test();
        t2.a();
    }
}
输出结果:
-----这是静态代码块
0
------b
------这是构造代码块
这是空参构造方法
-----a
这是普通代码块
----000000
10
------这是构造代码块
这是空参构造方法
-----a
这是普通代码块
----000000
10

总结

 想要学好Java,一定要注重编程思想的转变, 从面相流程编程,转换为面相对象编程,把属性和方法定义到一个对象类里,然后通过对象之间的交互协作,将编程的过程程式化!

;