1.1、 面向过程与面向对象的区别
面向过程编程:Process oriented programming(POP)
面向对象编程:object-oriented programming(OOP)
为什么会出现面向对象分析方法?
因为现实世界太复杂多变,面向过程的分析方法无法满足
面向过程?
采用面向过程必须了解整个过程,每个步骤都有因果关系,每个因果关系都构成了一个步骤,多个步骤就构成了一个系统,因为存在因果关系每个步骤很难分离,非常紧密,当任何一步骤出现问题,将会影响到所有的系统。如:采用面向过程生产电脑,那么他不会分CPU、主板和硬盘,它会按照电脑的工作流程一次成型。
面向对象?
面向对象对会将现实世界分割成不同的单元(对象),实现各个对象,如果完成某个功能,只需要将各个对象协作起来就可以。
1.2、 面向对象的三大特性
- 封装
- 继承
- 多态
1.3、 类与对象的概念
类是对具有共性事物的抽象描述,是在概念上的一个定义,那么如何发现类呢?
通常根据名词(概念)来发现类,如在成绩管理系统中:学生、班级、课程、成绩
学生—张三
班级—001
课程—J2SE
成绩—张三成绩
以上“张三”、“001”、“J2SE”和“张三的成绩”他们是具体存在的,称为对象,也叫实例
也就是说一个类的具体化(实例化),就是对象或实例
为什么面向对象成为主流技术,主要就是因为更符合人的思维模式,更容易的分析现实世界,所以在程序设计中也采用了面向对象的技术,从软件的开发的生命周期来看,基于面向对象可以分为三个阶段:
OOA(面向对象的分析)
OOD(面向对象的设计)
OOP(面向对象的编程)——-Java就是一个纯面向对象的语言
我们再进一步的展开,首先看看学生:
学生:学号、姓名、性别、地址,班级
班级:班级代码、班级名称
课程:课程代码、课程名称
成绩:学生、课程、成绩
大家看到以上我们分析出来的都是类的属性
接下来采用简易的图形来描述一下,来描述我们的概念(来源成绩管理系统的概念,来源于领域的概念,这个领域就是成绩系统管理领域)
以上描述的是类的属性,也就是状态信息,接下来,再做进一步的细化
通过以上分析,大家应该了解:
类=属性+方法
属性来源于类的状态,而方法来源于动作
以上模型完全可以使用面向对象的语言,如Java来实现
1.4、 类的定义
在Java中如何定义类?
具体格式:
类的修饰符class 类名extends 父对象名称 implements 接口名称 { 类体:属性和方法组成 }
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
- public : 对所有类可见。使用对象:类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
我们可以通过以下表来说明访问权限:
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public | Y | Y | Y | Y | Y |
protected | Y | Y | Y | Y/N | N |
default | Y | Y | Y | N | N |
private | Y | N | N | N | N |
【示例代码】
public class Student {
//学号
int id;
//姓名
String name;
//性别
boolean sex;
//地址
String address;
//年龄
int age;
}
以上属性称为成员变量,局部变量是在方法中定义的变量,方法的参数,方法的返回值,局部变量使用前必须初始化,而成员变量会默认初始化,初始化的值名为该类型的默认值
1.5、 对象的创建和使用
必须使用new创建出来,才能用。
【示例代码】
public class OOTest01 {
public static void main(String[] args) {
//创建一个对象
Student zhangsan = new Student();
System.out.println("id=" + zhangsan.id);
System.out.println("name=" + zhangsan.name);
System.out.println("sex=" + zhangsan.sex);
System.out.println("address=" + zhangsan.address);
System.out.println("age=" + zhangsan.age);
}
}
class Student {
//学号
int id;
//姓名
String name;
//性别
boolean sex;
//地址
String address;
//年龄
int age;
}
具体默认值如下:
类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
char | ‘\u0000’ |
float | 0.0f |
double | 0.0d |
boolean | false |
引用类型 | null |
对成员变量进行赋值
public class OOTest02 {
public static void main(String[] args) {
//创建一个对象
Student zhangsan = new Student();
zhangsan.id = 1001;
zhangsan.name = "张三";
zhangsan.sex = true;
zhangsan.address = "北京";
zhangsan.age = 20;
System.out.println("id=" + zhangsan.id);
System.out.println("name=" + zhangsan.name);
System.out.println("sex=" + zhangsan.sex);
System.out.println("address=" + zhangsan.address);
System.out.println("age=" + zhangsan.age);
}
}
class Student {
//学号
int id;
//姓名
String name;
//性别
boolean sex;
//地址
String address;
//年龄
int age;
}
一个类可以创建N个对象,成员变量只属于当前的对象(只属于对象,不属于类),只有通过对象才可以访问成员变量,通过类不能直接访问成员变量
以上程序存在缺点,年龄可以赋值为负数,怎么控制不能赋值为负数?
1.6、 面向对象的封装性
控制对年龄的修改,年龄只能为大于等于0并且小于等于120的值
public class OOTest03 {
public static void main(String[] args) {
//创建一个对象
Student zhangsan = new Student();
/*
zhangsan.id = 1001;
zhangsan.name = "张三";
zhangsan.sex = true;
zhangsan.address = "北京";
zhangsan.age = 20;
*/
zhangsan.setId(1001);
zhangsan.setName("张三");
zhangsan.setSex(true);
zhangsan.setAddress("北京");
zhangsan.setAge(-20);
System.out.println("id=" + zhangsan.id);
System.out.println("name=" + zhangsan.name);
System.out.println("sex=" + zhangsan.sex);
System.out.println("address=" + zhangsan.address);
System.out.println("age=" + zhangsan.age);
}
}
class Student {
//学号
int id;
//姓名
String name;
//性别
boolean sex;
//地址
String address;
//年龄
int age;
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
从上面的示例,采用方法可以控制赋值的过程,加入了对年龄的检查,避免了直接操纵student属性,这就是封装,封装其实就是封装属性,让外界知道这个类的状态越少越好。以上仍然不完善,采用属性仍然可以赋值,如果屏蔽掉属性的赋值,只采用方法赋值,如下:
public class OOTest04 {
public static void main(String[] args) {
//创建一个对象
Student zhangsan = new Student();
zhangsan.id = 1001;
zhangsan.name = "张三";
zhangsan.sex = true;
zhangsan.address = "北京";
zhangsan.age = 20;
/*
zhangsan.setId(1001);
zhangsan.setName("张三");
zhangsan.setSex(true);
zhangsan.setAddress("北京");
zhangsan.setAge(20);
*/
/*
System.out.println("id=" + zhangsan.id);
System.out.println("name=" + zhangsan.name);
System.out.println("sex=" + zhangsan.sex);
System.out.println("address=" + zhangsan.address);
System.out.println("age=" + zhangsan.age);
*/
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
以上采用private来声明成员变量,那么此时的成员变量只属于Student,外界无法访问,这样就封装了我们的属性,那么属性只能通过方法访问,通过方法我们就可以控制对内部状态的读取权利。
封装属性,暴露方法(行为)
1.7、 构造函数(构造方法,构造器,Constructor)
构造方法主要用来创建类的实例化对象,可以完成创建实例化对象的初始化工作,声明格式:
构造方法修饰词列表类名(方法参数列表)
构造方法修饰词列表:public、proteced、private
类的构造方法和普通方法一样可以进行重载
构造方法具有的特点:
- 构造方法名称必须与类名一致
- 构造方法不具有任何返回值类型,即没有返回值,关键字void也不能加入,加入后就不是构造方法了,就成了普通的方法了
- 任何类都有构造方法,如果没有显示的定义,则系统会为该类定义一个默认的构造器,这个构造器不含任何参数,如果显示的定义了构造器,系统就不会创建默认的不含参数的构造器了。
【代码示例】,默认构造方法(也就是无参构造方法)
public class ConstructorTest01 {
public static void main(String[] args) {
//创建一个对象
Student zhangsan = new Student();
zhangsan.setId(1001);
zhangsan.setName("张三");
zhangsan.setSex(true);
zhangsan.setAddress("北京");
zhangsan.setAge(20);
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//默认构造方法
public Student() {
//在创建对象的时候会执行该构造方法
//在创建对象的时候,如果需要做些事情,可以放在构造方法中
System.out.println("----------Student-------------");
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
【代码示例】,带参数的构造方法
public class ConstructorTest02 {
public static void main(String[] args) {
//调用带参数的构造方法对成员变量进行赋值
Student zhangsan = new Student(1001, "张三", true, "北京", 20);
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Student(int studentId, String studentName, boolean studentSex, String studentAddress, int studentAge) {
id = studentId;
name = studentName;
sex = studentSex;
address = studentAddress;
age = studentAge;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
【代码示例】,进一步理解默认构造方法
public class ConstructorTest03 {
public static void main(String[] args) {
//调用带参数的构造方法对成员变量进行赋值
//Student zhangsan = new Student(1001, "张三", true, "北京", 20);
Student zhangsan = new Student();
zhangsan.setId(1001);
zhangsan.setName("张三");
zhangsan.setSex(true);
zhangsan.setAddress("北京");
zhangsan.setAge(20);
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Student(int studentId, String studentName, boolean studentSex, String studentAddress, int studentAge) {
id = studentId;
name = studentName;
sex = studentSex;
address = studentAddress;
age = studentAge;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
出现错误,主要原因是默认构造函数不能找到,手动建立的构造方法,将会把默认的构造方法覆盖掉,所以在这种情况下必须显示的建立默认构造方法
public class ConstructorTest04 {
public static void main(String[] args) {
//调用带参数的构造方法对成员变量进行赋值
//Student zhangsan = new Student(1001, "张三", true, "北京", 20);
Student zhangsan = new Student();
zhangsan.setId(1001);
zhangsan.setName("张三");
zhangsan.setSex(true);
zhangsan.setAddress("北京");
zhangsan.setAge(20);
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//手动提供默认的构造函数
public Student() {}
public Student(int studentId, String studentName, boolean studentSex, String studentAddress, int studentAge) {
id = studentId;
name = studentName;
sex = studentSex;
address = studentAddress;
age = studentAge;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
以上示例执行正确,因为加入了默认的构造方法,同时也演示了构造方法的重载,构造方法重载原则和普通方法是一样。
1.8、 对象和引用
1.8.1、Java内存的主要划分
1.8.2、内存的表示
第一步,执行main方法,将main方法压入栈,然后new Student对象
//创建一个对象
Student zhangsan = new Student();
zhangsan.id = 1001;
zhangsan.name = "张三";
zhangsan.sex = true;
zhangsan.address = "北京";
zhangsan.age = 20;
1.8.3、当不使用new关键字时,出现的问题
```java public class OOTest05 {
public static void main(String[] args) {
//创建一个对象
//Student zhangsan = new Student();
Student zhangsan = null;
zhangsan.id = 1001;
zhangsan.name = "张三";
zhangsan.sex = true;
zhangsan.address = "北京";
zhangsan.age = 20;
System.out.println("id=" + zhangsan.id);
System.out.println("name=" + zhangsan.name);
System.out.println("sex=" + zhangsan.sex);
System.out.println("address=" + zhangsan.address);
System.out.println("age=" + zhangsan.age);
}
}
class Student {
//学号
int id;
//姓名
String name;
//性别
boolean sex;
//地址
String address;
//年龄
int age;
}
抛出了空指针异常,为什么会抛出此一样,因为zhangsan没有指向任何对象,所以zhangsan的地址为null,我们就使用student相关的属性,这样就导致了空指针异常<br />![1646724984(1).png](https://cdn.nlark.com/yuque/0/2022/png/23145762/1646724986594-5909f32b-2409-4f24-9e58-5508b6c56da3.png#clientId=u2e4c26ac-87ef-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=329&id=u54bdeaab&margin=%5Bobject%20Object%5D&name=1646724984%281%29.png&originHeight=494&originWidth=863&originalType=binary&ratio=1&rotation=0&showTitle=false&size=22333&status=done&style=shadow&taskId=u5bc30a73-a845-4322-9bd0-146f5820093&title=&width=575.3333333333334)
<a name="GlqqO"></a>
### **1.8.4、参数传递**
- 值传递
```java
public class OOPTest01 {
public static void main(String[] args) {
int m = 10;
add(m);
System.out.println("m="+m);
}
public static int add(int t){
t = t + 1;
System.out.println("t="+t);
return t;
}
}
以上代码执行过程,首先在栈中创建main方法栈帧,初始化m的值为10,将此栈帧压入栈,接着调用add()方法,通常是在栈区创建新的栈帧,并赋值t为10,压入栈中,两栈帧都是独立的,他们之间的值是不能互访的。然后add()方法栈帧弹出,接下来执行输出m值的语句,因为传递的是值,所以不会改变m的值,输出结果m的值仍然为10,最后将main方法栈帧弹出,main方法执行完毕。
结论:只要是基本类型,传递过去的都是值。(Java中只有值传递)
引用传递(传址) ```java public class OOTest07 {
public static void main(String[] args) {
//创建一个对象
Student student = new Student();
student.id = 1001;
student.name = "张三";
student.sex = true;
student.address = "北京";
student.age = 20;
method1(student);
System.out.println("id=" + student.id);
System.out.println("name=" + student.name);
System.out.println("sex=" + student.sex);
System.out.println("address=" + student.address);
System.out.println("age=" + student.age);
}
public static void method1(Student temp) {
temp.name="李四";
} }
class Student {
//学号
int id;
//姓名
String name;
//性别
boolean sex;
//地址
String address;
//年龄
int age;
}
![1646725094(1).png](https://cdn.nlark.com/yuque/0/2022/png/23145762/1646725097819-7791b8da-d0fe-4531-82e1-b2ecb12903b7.png#clientId=u2e4c26ac-87ef-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=292&id=ub2a3d2d1&margin=%5Bobject%20Object%5D&name=1646725094%281%29.png&originHeight=438&originWidth=824&originalType=binary&ratio=1&rotation=0&showTitle=false&size=32672&status=done&style=shadow&taskId=uf759b98d-d41c-450c-be1b-87c83207beb&title=&width=549.3333333333334)<br />以上执行流程为,<br />1、 执行main方法时,会在栈中创建main方法的栈帧,将局部变量student引用保存到栈中<br />2、 将Student对象放到堆区中,并赋值<br />3、 调用method1方法,创建method1方法栈帧<br />4、 将局部变量student引用(也就是student对象的地址),传递到method1方法中,并赋值给temp<br />5、 此时temp和student引用指向的都是一个对象<br />6、 当method1方法中将name属性改为“李四”时,改的是堆中的属性<br />7、 所以会影响输出结果,最后的输出结果为:李四<br />8、 main方法执行结束,此时的student对象还在堆中,我们无法使用了,那么他就变成了“垃圾对象”,java的垃圾收集器会在某个时刻,将其清除<br />以上就是址传递,也就是引用的传递<br />**结论:除了基本类型外都是值传递**
<a name="EBNNK"></a>
## **1.9、 this关键字**
this关键字指的是当前调用的对象,如果有100个对象,将有100个this对象指向各个对象<br />this关键字可以使用在:
- 当局部变量和成员变量重名的时候可以使用this指定调用成员变量
- 在一个构造方法中通过this调用另一个构造方法
需要注意:this只能用在构造函数和成员方法内部,还可以应用在成员变量的声明上,static标识的方法里是不能使用this的,关于static以后再讲
<a name="F4kij"></a>
### **1.9.1、当局部变量和成员变量重名的时候可以使用this指定调用成员变量**
```java
public class OOTest08 {
public static void main(String[] args) {
Student zhangsan = new Student();
zhangsan.setId(1001);
zhangsan.setName("张三");
zhangsan.setSex(true);
zhangsan.setAddress("北京");
zhangsan.setAge(20);
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//设置学号
public void setId(int id) {
id = id;
}
//读取学号
public int getId() {
return id;
}
public void setName(String name) {
name = name;
}
public String getName() {
return name;
}
public void setSex(boolean sex) {
sex = sex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String address) {
address = address;
}
public String getAddress() {
return address;
}
public void setAge(int age) {
age = age;
}
public int getAge() {
return age;
}
}
输出错误,输出的都是成员变量的默认值,赋值没有起作用,这是为什么?
如:setId(int id) 方法中,我们的赋值语句为id=id,这样写Java无法知道是向成员变量id赋值,它遵循“谁近谁优先”,当然局部变量优先了,所以会忽略成员变量
【代码示例】,修正以上代码
public class OOTest09 {
public static void main(String[] args) {
Student zhangsan = new Student();
zhangsan.setId(1001);
zhangsan.setName("张三");
zhangsan.setSex(true);
zhangsan.setAddress("北京");
zhangsan.setAge(20);
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//设置学号
public void setId(int id) {
this.id = id;
}
//读取学号
public int getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setSex(boolean sex) {
this.sex = sex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
通过this可以取得当前调用对象,采用this明确指定了成员变量的名称,所以就不会赋值到局部变量,了解狭义和广义上的javabean的概念
1.9.2、通过this调用另一个构造方法
通过new调用当前对象的构造函数(这样是不对的)
public class OOTest10 {
public static void main(String[] args) {
//Student zhangsan = new Student(1001, "张三", true, "北京", 20);
//Student zhangsan = new Student(1001, "张三");
Student zhangsan = new Student(1002, "李四");
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Student(int id, String name) {
/*
this.id = id;
this.name = name;
this.sex=true;
this.address="北京";
this.age=20;
*/
//调用构造函数,部分值采用默认值
new Student(id, name, true, "北京", 20);
}
public Student(int id, String name, boolean sex, String address, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
通过this调用当前对象的构造函数 ```java public class OOTest11 {
public static void main(String[] args) {
Student zhangsan = new Student(1002, "李四");
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Student(int id, String name) {
/*
this.id = id;
this.name = name;
this.sex=true;
this.address="北京";
this.age=20;
*/
//调用构造函数,部分值采用默认值
//new Student(id, name, true, "北京", 20);
//采用this调用当前对象对象的构造函数,不能采用new,以上调用时错误的
this(id, name, true, "北京", 20);
}
public Student(int id, String name, boolean sex, String address, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
以上输出正确
<a name="JhDKe"></a>
## **1.10、 static关键字**
static修饰符可以修饰:变量、方法和代码块
- 用static修饰的变量和方法,可以采用类名直接访问
- 用static声明的代码块为静态代码块,JVM第一次使用类的时候,会执行静态代码块中的内容
<a name="XfV9K"></a>
### **1.10.1、采用静态变量实现累加器**
【代码示例】
```java
public class StaticTest01 {
public static void main(String[] args) {
Student student1 = new Student(1001, "张三", true, "北京", 20);
Student student2 = new Student(1002, "李四", true, "上海", 30);
System.out.println(student1.getCount());
System.out.println(student2.getCount());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//计数器,计算student的创建个数
private int count;
public Student(int id, String name, boolean sex, String address, int age) {
count++;
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//返回计数器
public int getCount() {
return count;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
以上输出不正确,因为采用的是成员变量作为累加器,成员变量只属于某一个对象,如果多个对象那么成员变量会有多个拷贝,对象中的成员变量都是私有的,某一个对象中的成员变量的改变不会影响到另一个对象中的成员变量的改变
【代码示例】
public class StaticTest02 {
public static void main(String[] args) {
Student student1 = new Student(1001, "张三", true, "北京", 20);
Student student2 = new Student(1002, "李四", true, "上海", 30);
System.out.println(student1.getCount());
System.out.println(student2.getCount());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//计数器,计算student的创建个数
private static int count;
public Student(int id, String name, boolean sex, String address, int age) {
count++;
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//返回计数器
public int getCount() {
return count;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
static声明的变量,所有通过该类new出的对象,都可以共享,通过该对象都可以直接访问
static声明的变量,也可以采用类直接访问,所以我们也称其为类变量
【代码示例】,采用类直接访问count
public class StaticTest03 {
public static void main(String[] args) {
Student student1 = new Student(1001, "张三", true, "北京", 20);
Student student2 = new Student(1002, "李四", true, "上海", 30);
//System.out.println(student1.getCount());
//System.out.println(student2.getCount());
System.out.println(Student.count);
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//计数器,计算student的创建个数
static int count;
public Student(int id, String name, boolean sex, String address, int age) {
count++;
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//返回计数器
public int getCount() {
return count;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
通过以上分析,static声明的变量会放到方法区中,static声明的变量只初始化一次,加在类的时候初始化,如果多个静态变量,会按照静态变量在类中的顺序进行初始化。
1.10.2、静态方法中访问实例变量、实例方法或this关键字
静态方法中是不能直接调用实例变量、实例方法和使用this的,也就是说和实例相关的他都不能直接调用
【示例代码】,在静态区域中调用实例方法
public class StaticTest04 {
public static void main(String[] args) {
//在静态区域中不能直接调用成员方法
//因为静态方法的执行不需要new对象
//而成员方法必须new对象后才可以执行
//所以执行静态方法的时候,对象还没有创建
//所以无法执行成员方法
method1();
}
public void method1() {
System.out.println("method1");
}
}
【代码示例】,改善以上程序,在静态区域中成功调用实例方法
public class StaticTest05 {
public static void main(String[] args) {
StaticTest05 staticTest05 = new StaticTest05();
//在静态区域中如果访问成员方法必须具有
//该成员方法对应的对象引用
staticTest05.method1();
}
public void method1() {
System.out.println("method1");
}
}
【代码示例】,改善以上程序,在静态区域中可以直接调用静态方法
public class StaticTest06 {
public static void main(String[] args) {
//可以直接调用
//method1();
//可以采用类名+方法调用
StaticTest06.method1();
}
public static void method1() {
System.out.println("method1");
}
}
【代码示例】,在静态区域中调用成员(实例)变量
public class StaticTest07 {
//private int age = 100;
private static int age = 100;
public static void main(String[] args) {
//在静态区域中无法直接访问成员变量
//System.out.println(age);
//可以采用对象的引用调用
//StaticTest07 staticTest07 = new StaticTest07();
//System.out.println(staticTest07.age);
//直接取得静态变量的值
//System.out.println(age);
//可以采用类名+属性名 访问
System.out.println(StaticTest07.age);
}
}
【代码示例】,在静态区域中使用this
public class StaticTest08 {
private int age = 100;
public static void main(String[] args) {
//因为执行main方法的时候,还没有该对象
//所以this也就不存在,无法使用
System.out.println(this.age);
}
}
1.10.3、静态方法的初始化顺序
上面已经说到,静态变量,在类加载时就会初始化,也就是将类的字节码读取到方法区时就会初始化
【代码示例】
public class StaticTest09 {
private static int age = 100;
static {
System.out.println("---------静态语句块1---------");
}
static {
System.out.println("---------静态语句块2---------");
}
static {
System.out.println("---------静态语句块3---------");
}
static {
System.out.println("---------静态语句块4---------");
System.out.println("age=" + age);
}
public static void main(String[] args) {
System.out.println("-------------main----------------");
}
}
Static声明的变量或static语句块在类加载时就会初始化,而且只初始化一次
1.10.4、解释main方法
解释main方法:
public:表示全局所有,其实就是封装性
static:静态的,也就是说它描述的方法只能通过类调用
main:系统规定的
String[] args 参数类型也是系统规定的
以上为什么是静态方法,应该很显然,这样java虚拟机调用起来会更方便,直接拿到类就可以调用main方法了,而静态的东西都在方法区中,那么你在静态方法里调用成员属性,他在方法区中无法找到,就算到堆区中查找,可能此成员属性的对象也没有创建,所以静态方法中是不能直接访问成员属性和成员方法的。
1.11、 单例模式初步
什么是设计模式:设计模式是可以重复利用的解决方案
设计模式的提出是在1995年,是由4人组作者提出的,称为GoF,也就是“四人组”
设计模式从结构上分为三类:
- 创建型
- 结构性
- 行为型
其中最简单的设计模式就是单例了,单例这种模式,尽量少用,也有将其称为“反模式”,关于缺点以后做项目时再说
单例模式有什么好处
我们知道对象实例创建完成后,会放到堆中,如果堆中的实例过多,将会存在特别多的垃圾,这样会导致一些问题,如内存溢出等,使用单例模式后,只会创建一个实例,显著减少对象实例的个数,同时也会提高性能,因为不会频繁的创建对象,这只是他的一个好处,其他方面项目中再说。
单例模式的三要素:
- 在类体中需要具有静态的私有的本类型的变量
- 构造方法必须是私有的
提供一个公共的静态的入口点方法 ```java public class SingletonPatternTest01 {
public static void main(String[] args) {
//Singleton s1 = new Singleton();
//Singleton s2 = new Singleton();
//............
Singleton.getInstance().test();
} }
class Singleton {
//静态私有的本类的成员变量
private static Singleton instance = new Singleton();
//私有的构造方法
private Singleton() {
}
//提供一个公共的静态的入口点方法
public static Singleton getInstance() {
return instance;
}
public void test() {
System.out.println("----------test----------");
}
} ```