初识java - 类和对象

一,面向对象的初步认知

1.1 什么是面向对象

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

1.2 面向对象与面向过程

  一开始的时候,并没有面向对象,只有面向过程的概念。面向过程很好理解,指的是程序员接到需求,会把它拆成一个一个的命令,然后串起来交给计算机去执行(例如c中如何实现函数)。
而面向对象就有一点不同了,他并不是要将实现这个过程的细节给列举,而是将目标实现的过程给列举。
举个例子,产品经理说要把大象装进冰箱里。程序员列了几个步骤:

  • 把冰箱门儿打开。
  • 把大象装进去。
  • 把冰箱门儿关上。

上面每一个步骤,程序员都会用一个「函数」来实现。「函数」是一些代码的集合体,每个函数可以实现一个功能,而这就是面向对象。

二, 类定义和使用

2.1 简单认识类

类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性(外观尺寸等),哪些功能(用来干
啥),描述完成后计算机就可以识别了。

比如:洗衣机,它是一个实体,在Java中可以将其看成是一个类。
属性:产品品牌,型号,产品重量,外观尺寸,颜色…
功能:洗衣,烘干、定时…

那在Java语言中,如何对上述的洗衣机类来进行定义呢?

2.2 类的定义格式

在java中定义类时需要用到class关键字,具体语法如下
class为定义类的关键字,ClassName为类的名字,{}中为类的主体。

// 创建类
class ClassName{
field; // 字段(属性) 或者 成员变量
method; // 行为 或者 成员方法
}

类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法

2.3类的注意事项

  • 类名注意采用大驼峰定义
  • 一般一个文件当中只定义一个类
  • main方法所在的类一般要使用public修饰(注意:Eclipse默认会在public修饰的类中找main方法)
  • public修饰的类必须要和文件名相同
  • 不要轻易去修改public修饰的类的名称,如果要修改,通过开发工具修改。
  • 一个.java文件中只能有一个public类。

2.4局部变量,成员变量及成员变量和全局变量的关系

public class ClassName {
    //这个a为成员变量,同时也叫字段(属性)因为是在内中定义的
    public int a;
    //这个c也为成员变量(字段,属性)(但同时也有人叫他为全局变量,因为他被由static关键字所修饰)
    //当然不要纠结这是为什么,在后面的static成员中会作出解释
    public static int c;
    public static void main(String[] args) {
        //这个b叫做局部变量,因为他是定义在方法中的
        int b = 0;
    }
}

  • 成员变量可以不用初始化(默认:基本类型大多为0 ,引用类型为null)
  • 局部变量必须初始化(不然编译会报错)

三, 类的实例化

3.1 什么是实例化

用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象。

//定义了一个人类
 class Person {
    //人的属性
    public String name;//名字
    public int age;//年龄
    
    //人的行为(成员方法)
    public void eat(){//吃饭
        System.out.println("年龄为" + age + "的" + name + " 正在吃饭");
    }
    public void sleep(){//睡觉
        System.out.println("年龄为" + age + "的" + name + " 正在睡觉");
    }
}
public class Test {
    public static void main(String[] args) {
        //这就是实例化对象
        Person person = new Person();

        //用对象实例加 . 来调用对象中的属性和方法
        person.name = "张三";
        person.age = 20;
        person.eat();
        person.sleep();
    }
}

    ----------------------
    年龄为20的张三 正在吃饭
	年龄为20的张三 正在睡觉

四, this引用

4.1 什么是this引用

  this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

  • 注意:this引用的是调用成员方法的对象。

4.2this引用的作用

  在编程过程中我们会遇到这样的情况,以构造函数举例(构造函数下面会有讲解):在初识化成员变量时会有以下情况

public class Test {
    public static void main(String[] args) {
        //这就是实例化对象
        Person person = new Person("张三",20);
        person.sleep();
        person.eat();
    }
}
//定义了一个人类
class Person {
    //人的属性
    public String name;//名字
    public int age;//年龄
    //无参构造方法
    public Person() {
    }
    //带参构造方法
    public Person(String name, int age) {
        name = name;
        age = age;
    }
    //人的行为(成员方法)
    public void eat(){//吃饭
        System.out.println("年龄为" + age + "的" + name + " 正在吃饭");
    }
    public void sleep(){//睡觉
        System.out.println("年龄为" + age + "的" + name + " 正在睡觉");
    }
}
-------------------
预想结果:
年龄为20的张三 正在睡觉
年龄为20的张三 正在吃饭
实际结果:
年龄为0null 正在睡觉
年龄为0null 正在吃饭

  我们在实例化的时候已经赋值了但是结果却和我们预想的不同,而之所以会出现这种情况,原因就在带参构造方法那里:

 //带参构造方法
    public Person(String name, int age) {
        name = name; //这里的name产生了歧义
        age = age; //这里的age产生了歧义
    }

我们想象的在这里插入图片描述
但实际上的
在这里插入图片描述

  可是计算机却不知道谁是谁的name,age计算机在执行这种代码时遵循一个原则(就近原则),谁近就用谁,所以就导致带参构造方法中的代码成了无效代码,而类中的成员变量也未得到初始化,但是成员变量未初始化的情况下,系统会给成员变量默认初始化,基本数据类型为0(bool除外),引用数据类型为null。
这就造成了我们说看到的和分析的不同:

预想结果:
年龄为20的张三 正在睡觉
年龄为20的张三 正在吃饭
实际结果:
年龄为0的null 正在睡觉
年龄为0的null 正在吃饭

而我们要如何来改变这种情况呢!这就使用到了this关键字:

public class Test {
    public static void main(String[] args) {
        //这就是实例化对象
        Person person = new Person("张三",20);
        person.sleep();
        person.eat();
    }
}
//定义了一个人类
class Person {
    //人的属性
    public String name;//名字
    public int age;//年龄
    //无参构造
    public Person() {
    }
    //带参构造
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //人的行为(成员方法)
    public void eat(){//吃饭
        System.out.println("年龄为" + age + "的" + name + " 正在吃饭");
    }
    public void sleep(){//睡觉
        System.out.println("年龄为" + age + "的" + name + " 正在睡觉");
    }
}
-------------------------
预想结果:
年龄为20的张三 正在睡觉
年龄为20的张三 正在吃饭
实际结果:
年龄为20的张三 正在睡觉
年龄为20的张三 正在吃饭

而这就是加了this关键字后其中name,age的指向
在这里插入图片描述

4.3 this引用的特性

    1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
    1. this只能在"成员方法"中使用
    1. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象
  •  4. this(…)必须是构造方法中第一条语句
    1. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收。
      在代码层面来简单演示—>注意:下图右侧中的Date类也是可以通过编译的
      在这里插入图片描述

4.4this调用

  • 调用成员属性 – this.data
  • 调用成员方法 – this.func()
  • 调用构造方法 – this()
	//无参构造
    public Person() {
        this("张三",20);//调用有参
    }
    //带参构造
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

【注意】
1).this()必须放在第一行
2).this()只能存在构造方法中
3).this不能调用静态成员和静态方法

五, 构造方法及对对象的初始化

5.1构造方法

5.1.1概念

构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
注意:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。

5.1.2 特性
    1. 名字必须与类名相同
    1. 没有返回值类型,设置为void也不行
    1. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
    1. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
  •  5. 如果没有自己写构造方法,编译器会自动帮你形成一个不带参数的构造方法,但是如果自己写了构造方法,编译器就不会自动生成无参构造方法。
public class Date {
	public int year;
	public int month;
	public int day;
	// 构造方法:
	// 名字与类名相同,没有返回值类型,设置为void也不行
	// 一般情况下使用public修饰
	// 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
	public Date(int year, int month, int day){
		this.year = year;
		this.month = month;
		this.day = day;
		System.out.println("Date(int,int,int)方法被调用了");
	}
	public void printDate(){
		System.out.println(year + "-" + month + "-" + day);
	}
	public static void main(String[] args) {
		// 此处创建了一个Date类型的对象,并没有显式调用构造方法
		Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了
		d.printDate(); // 2021-6-9
	}
}
public class Date {
	public int year;
	public int month;
	public int day;
	// 无参构造方法
	public Date(){
		this.year = 1900;
		this.month = 1;
		this.day = 1;
	}
  • 上述两个构造方法:名字相同,参数列表不同,因此构成了方法的重载。
  • 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。
  • 构造方法不能形成环
public Date(){
	this(1900,1,1);
}
public Date(int year, int month, int day) {
	this();
}
/*
无参构造器调用三个参数的构造器,而三个参数构造器有调用无参的构造器,形成构造器的递归调用
编译报错:Error:(19, 12) java: 递归构造器调用
*/

5.2对象的初始化

5.2.1 默认初始化

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

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

  2. 为对象分配内存空间

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

  4. 初始化所分配的空间
    即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:
    在这里插入图片描述

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

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

5.2.2一个简单题,带你初步了解jvm在实例化对象时的代码执行情况
class X{
	Y y=new Y();//1
	public X(){//2
		System.out.print("X");
	}
}
class Y{
	public Y(){//3
		System.out.print("Y");
	}
}
public class Z extends X{
	Y y=new Y();//4
	public Z(){//5
		System.out.print("Z");
	}
	public static void main(String[] args) {
		new Z();
	}
}
//-----------------------
//输出:YXYZ
5.2.3 就地初始化

在声明成员变量时,就直接给出了初始值。


public class Date {
	public int year = 1900;
	public int month = 1;
	public int day = 1;
	//无参构造
	public Date(){
	}
	//带参构造
	public Date(int year, int month, int day) {
	}
	public static void main(String[] args) {
		Date d1 = new Date(2021,6,9);
		Date d2 = new Date();
	}
}

六, 封装

  面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节

6.1 封装的概念

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。

6.2 访问限定符

在这里插入图片描述
public:可以理解为一个人的外貌特征,谁都可以看得到。
default: 对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了。
private:只有自己知道,其他人都不知道。
【说明】
protected主要是用在继承中,继承部分详细介绍。
default权限指:什么都不写时的默认权限。
访问权限除了可以限定类中成员的可见性,也可以控制类的可见性。
注意:一般情况下成员变量设置为private,成员方法设置为public。

6.3 包的概念

在这里插入图片描述
这里的testDemo,Testone,testtwo,都为互不相同的包,中和上面(6.2访问限定符表)就可以理解访问限定修饰符的作用范围了。

在用到其他包的类时就需要导包,用import关键字来进行导包。
【注意】

  • 只能导入指定的类
    import testDemo.Testtwo.Test2;
  • 不能导入指定的包
    import testDemo.Testtwo;
    这里编译器会报错

七, static成员

7.1 static修饰成员变量

static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。

【静态成员变量特性】
1). 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
2). 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问
3). 类变量存储在方法区当中
4). 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)

7.2 static修饰成员方法

Java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态成员一般是通过静态方法来访问的。

【静态方法特性】
1). 不属于某个具体的对象,是类方法
2). 可以通过对象调用,也可以通过类名.静态方法名(…)方式调用,更推荐使用后者
3). 不能在静态方法中访问任何非静态成员变量
4). 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用
5). 静态方法无法重写,不能用来实现多态(此处大家暂时不用管,后序多态位置详细讲解)。

7.3 static成员变量初始化

注意:静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性
静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化。

  1. 就地初始化
    就地初始化指的是:在定义时直接给出初始值
    在这里插入图片描述

  2. 静态代码块初始化
    那什么是代码块呢?继续往后看 😃 😦

八, 代码块

8.1 代码块概念以及分类

使用 {} 定义的一段代码称为代码块(只执行一次)。根据代码块定义的位置以及关键字,又可分为以下四种:

  • 普通代码块
  • 构造块
  • 静态块
  • 同步代码块

8.2 普通代码块

普通代码块:定义在方法中的代码块(用法较少见)

public class Test3 {
    public static void main(String[] args) {
        Person person = new Person("张三",20);
        System.out.println(person.getName() +" "+ person.getAge());
       
        {
            //这是普通代码块
        }
        
    }
}

8.3 构造块

构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。(用到较多)

	//实例成员变量
    private String name;
    private int age;
    //这是示例代码块
    {
        this.name = "李华";
        this.age = 20;
    }

8.4 静态块

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

 	//静态成员变量
    public static int num;
    //这是静态代码块
    static {
        num = 20;
    }

【注意事项】

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

8.5成员变量,代码块与类实例化时的一些先后实现顺序

**优先静态成员和静态代码块(先于实例化对象前)(谁在前谁先被调用)-> 构造代码块 -> 构造方法 **

  • 当实例化对象时,构造代码块会被拷贝到构造方法里面最上面执行。

九, 内部类

顾名思义,在类里面定义的类。

【注意事项】
1). 定义在class 类名{}花括号外部的,即使是在一个文件里,都不能称为内部类
2). 内部类和外部类共用同一个java源文件,但是经过编译之后,内部类会形成单独的字节码文件

根据内部类定义的位置不同,一般可以分为以下几种形式:
1). 成员内部类(普通内部类:未被static修饰的成员内部类 和 静态内部类:被static修饰的成员内部类)
2). 局部内部类(不谈修饰符)、匿名内部类
注意:内部类其实日常开发中使用并不是非常多,大家在看一些库中的代码时候可能会遇到的比较多,日常开始中使用最多的是匿名内部类

十, 对象的打印(cv程序猿)

public class Person {
	String name;
	String gender;
	int age;
	public Person(String name, String gender, int age) {
		this.name = name;
		this.gender = gender;
		this.age = age;
		//如果想要默认打印对象中的属性该如何处理呢?答案:重写toString方法即可。
	}
	public static void main(String[] args) {
		Person person = new Person("Jim","男", 18);
		System.out.println(person);
	}
}
// 打印结果:day20210829.Person@1b6d3586


public class Person {
	String name;
	String gender;
	int age;
	public Person(String name, String gender, int age) {
		this.name = name;
		this.gender = gender;
		this.age = age;
	}
	@Override//方法重写
	public String toString() {
		return "[" + name + "," + gender + "," + age + "]";
	}
	public static void main(String[] args) {
		Person person = new Person("Jim","男", 18);
		System.out.println(person);
	}
}
// 输出结果:[Jim,男,18]

11. 每日一问

类和对象:

  • 什么类? 什么是对象? 什么是面向对象? 什么是面向过程?
  • 如何定义一个类?
  • 如何实例化一个对象?
  • 通过对象如何访问对象的成员属性/成员变量 对象的成员方法通过对象.访问
  • this引用?
  • 构造方法?
  • 引用指向null代表什么? 引用指向引用可以吗? 一个引用是否可以指向多个对象?
  • 什么是封装?
  • 对类的细节进行隐藏? 提供公开的接口来进行和数据进行交互!!
  • 包的概念? 如何导包?
  • 对成员变量,局部变量,由static关键字修饰的成员变量的 关系 和 内存 分布知道?
  • 代码块? 作用?
  • 程序运行时的 成员变量 代码块 构造方法 及由static修饰后的 成员变量 代码块 的运行顺序?
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值