一.什么是面向对象
面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。
面向过程编程 → 关注的是过程。
面向对象编程 → 关注的是对象 → 1.找对象 2.创建对象 3.使用对象
注意:不管是面向过程还是面向对象,它并不是一门语言,而是解决问题的方法。
二.类的定义和使用
-
类是用来对一个实体(对象)来进行描述的,而对象是一个真正存在的实体。
-
类的定义格式:
class 类名{
字段/属性;
方法;
………
}
class为定义类的关键字,{}中为类的主体。类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法。
注意事项:
-
类名注意采用大驼峰定义。
-
成员前用什么访问修饰限定符看需求自行添加。
-
方法是否用static自行判断。
-
局部变量在使用的时候需要进行初始化,但成员变量会有一个默认值,遵循的原则是:
1)引用类型默认为null
2)基本数据类型默认为0。
-
练习:
定义一个狗类:
public class Dog {
public String name;
public int age;
public void eat(){
System.out.println(this.name + "吃狗粮");
}
}
注意事项:
- 一般一个文件当中只定义一个类。
- main方法所在的类一般要使用public修饰(注意:Eclipse默认会在public修饰的类中找main方法)。
- public修饰的类必须要和文件名相同。
- 不要轻易去修改public修饰的类的名称。
三.类的实例化
- 什么是实例化
定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过int和double是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:PetDog类和Student类。它们都是类(一种新定义的类型)有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)。
用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象。
而每次new一个对象的时候,都会在堆上创建出该对象。
下来我们看一段代码:
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
System.out.println(dog.name);
System.out.println(dog.age);
int a;
System.out.println(a);//这里会报错
}
}
我们知道局部变量在使用的时候,要进行初始化,否则就会报错。但是,观察上段代码,我们会发现dog.name和dog.age没有初始化,但编译器也没有报错,这是因为成员变量会有一个默认值。
这个默认值遵循的规则:
- 引用类型默认为null
- 基本数据类型默认为对应的0值
注意事项:
- new 关键字用于创建一个对象的实例。
- 使用 . 来访问对象中的属性和方法。
- 同一个类可以创建对个实例。
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "小黑";
dog.age = 1;
System.out.println(dog.name);
System.out.println(dog.age);
Dog dog2 = new Dog();
dog2.name = "小黄";
dog2.age = 10;
System.out.println(dog2.name);
System.out.println(dog2.age);
}
-
类和对象的说明
1) 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
2) 类是一种自定义的类型,可以用来定义变量.
3) 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
4) 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。
四.this引用
先来看一段代码:
public class Date {
public int year;
public int month;
public int day;
public void setDate(int y, int m, int d) {
year = y;
month = m;
day = d;
}
public void printDate() {
System.out.println(year + "/" + month + "/" + day);
}
public static void main(String[] args) {
Date d1 = new Date();
Date d2 = new Date();
Date d3 = new Date();
d1.setDate(1999,1,1);
d2.setDate(2000,1,1);
d3.setDate(2001,1,1);
//打印日期中的内容
d1.printDate();
d2.printDate();
d3.printDate();
}
}
这样子看是没有什么错误。那我们换个写法,也就是:
- 为什么要有this引用
方法中,当我们写一个方法对成员变量进行初始化的时候,形参名不小心与成员变量名相同:
public void setDate(int year, int month, int day) {
year = year;
month = month;
day = day;
}
最终结果输出为:
那函数体中到底是谁给谁赋值?成员变量给成员变量?参数给参数?参数给成员变量?成员变量参数?估计自己都搞不清楚了。
结果:形参自己给自己复制,并没有修改到对象中的year,month,day。
原因:此时,在方法内,year,month,day都是局部变量,此时局部变量优先使用。
解决办法:使用 this。
public void setDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
- 什么是this引用
this代表当前对象的引用,this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
- this引用的三种用法:
1)通过this访问当前对象的成员变量。
2)通过this访问当前对象的非静态方法。
3)通过this()访问当前对象的其他构造方法。
注意:this不能在静态方法当中使用。
五.对象的构造及初始化
通过前面知识点的学习知道,在Java方法内部定义一个局部变量时,必须要初始化,否则会编译失败。如果是对象:
public static void main(String[] args) {
Date d1 = new Date();
d1.setDate(1999,1,1);
d1.printDate();
}
需要调用之前写的SetDate方法才可以将具体的日期设置到对象中。通过上述例子发现两个问题:
- 每次对象创建好后调用setDate方法设置具体日期,比较麻烦,那对象该如何初始化?
- 局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?
构造方法
- 概念
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
普通方法与构造方法的区别:
注意:
1)构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。
2)一个对象的生成至少两步很重要 :
(1)为对象分配内存。
(2)调用合适的(不止一种)构造方法。
3)实例化对象的时候,一定会调用构造方法。
我们因此也就可以改一下上面的代码了:
public class Date {
public int year;
public int month;
public int day;
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate() {
System.out.println(year + "/" + month + "/" + day);
}
public static void main(String[] args) {
Date d1 = new Date(2015, 1, 1);
d1.printDate();
}
}
-
可能有人想到了刚刚 new对象的时候不是没写过任何构造方法吗?
这是因为当你没有写任何构造方法的时候,Java会帮你提供一个默认的不带参数的构造方法,但是一旦你有其他的构造方法,Java就不会再给你提供不带参数的构造方法了。
-
特性
-
名字必须与类名相同。
-
没有返回值类型,设置为void也不行。
-
创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)。
-
构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)。
public class Date { public int year; public int month; public int day; public Date(){ System.out.println("这是不带参数的构造方法"); } public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } }
-
如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。但是一旦你有其他的构造方法,Java就不会再给你提供不带参数的构造方法了。
-
构造方法中,可以通过this调用其他构造方法来简化代码。
注意:
-
this(…)必须是构造方法中第一条语句。
-
不能形成环;
我们可以借助IDEA来自动生成构造方法:
-
默认初始化
在上文中提出的第二个问题:为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?
要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:
Date d = new Date(1999,1,1);
在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
-
检测对象对应的类是否加载了,如果没有加载则加载
-
为对象分配内存空间
-
处理并发安全问题
比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突
-
初始化所分配的空间
即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如
-
设置对象头信息
-
调用构造方法,给对象中各个成员赋值
就地初始化
在声明成员变量时,就直接给出了初始值。
注意:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中。