第3章 面向对象(上)
学习目标
- 了解面向对象的思想,能够说出面向对象的三个特性:(访问)封装、(对象)继承、(方法)多态
- 掌握类的定义,能够独立完成类的定义
- 掌握对象的创建和使用,能够完成对象创建,用对象访问对象属性和方法
- 掌握对象的引用传递,能够独立实现对象的引用传递
- 熟悉Java的4种访问控制权限,能够在类中灵活使用访问控制权限
- 熟悉类的封装特性,能够说出为什么要封装以及如何实现封装
- 掌握构造方法的定义和重载,能够独立定义构造方法,重载构造方法
- 熟悉this关键字,能够使用this调用成员属性、成员方法、构造方法
- 了解代码块的应用,能够说出普通代码块和构造块的特点
- 熟悉static关键字的使用,能够说出静态(属性、方法、代码块)的特点
1. 面向对象的思想
面向对象是相对于面向过程来讲的,是一种符合人类思维习惯的编程思想。
面向对象方法学认为,客观世界由对象组成。任何事物都是对象,每个对象都有自己的内部状态(特性、属性)和运动规律(方法、函数),不同对象彼此间通过消息相互作用、相互联系,从而构成了我们所要分析和构造的系统。系统中每个对象都属于一个特定的对象类。类是对具有相同属性和行为(方法)的一组相似对象的抽象定义。
客观世界 = Σ 对象
对象 = 属性s + 方法s
不同类之间相互作用、相互联系
类和对象:
- 类是具有相同属性和方法一组(一些)对象的抽象;
- 对象是类的实例化结果、是能够看得到摸的着的真实存在的实体。
面向对象是把构成问题的事物按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。
(1) 封装性
封装是面向对象的核心思想,指访问的封装性。它有两层含义:
- 第一层含义是指把对象的属性和行为(方法)看成是一个密不可分的整体,将这两者“封装”在一起(即封装在对象中);
- 另外一层含义指“信息隐藏”,将不想让外界知道的信息隐藏起来
(2) 继承性
继承性主要描述的是类与类之间的关系,通过继承,可以在原有类的基础上,对原有类的功能进行扩展。
(3) 多态性
多态性是指在一个类中同名方法(但参数类型、个数或顺序不同)或子类覆盖父类同名方法而执行不同的行为。
Java多态实现的三种形式,包括方法重载、方法重写和接口。
- 方法重载指的是在同一个类中定义多个同名方法,但方法的参数类型、个数或顺序不同。
- 方法重写指的是子类重新实现了父类中的某个方法,这个过程也称为方法覆盖(重写)。
- 子类方法的名称、参数类型以及返回类型与父类方法完全一致
- 子类方法的访问级别不能低于父类方法,即子类方法不能降低父类方法的访问级别
- 子类方法的异常类的类型不能超过父类方法的范围
- 接口是Java中重要的机制之一,接口定义了一组方法的签名,而这些方法由实现接口的类来具体实现。接口的实现可以增加代码的可扩展性和复用性。
2. 类与对象
2.1 类的定义
类是对象的抽象,用于描述一组对象的共同特征和行为。
类中可以定义成员变量和成员方法,其中:
- 成员变量用于描述对象的特征,成员变量也被称作对象的属性;
- 成员方法用于描述对象的行为,可简称为方法。
类 = 成员变量s + 成员方法s
class 类名{
成员变量s;
成员方法s;
}
package cn.zxx.ch03.ex00;
public class Student {
// 1.属性 -- 特征
String 姓名;
int 年龄;
String 性别;
// 2.方法--行为
public void study(){
System.out.println(姓名+"正在学习");
}
public void play() {
System.out.println(姓名 + "正在玩游戏");
}
}
局部变量与成员变量的不同
在Java中,定义在类中的变量被称为成员变量,定义在方法中的变量被称为局部变量。
----如果在某一个方法中定义的局部变量与成员变量同名,这种情况是允许的。此时,在方法中通过变量名访问到的是局部变量,而并非成员变量。
package cn.zxx.ch03.ex00;
public class Example1_jxp {
public static void main(String[] args) {
System.out.println("【例题】局部变量与成员变量同名,方法中通过变量名访问到的是局部变量 (张晓轩)");
Student1 stu = new Student1(); // 创建第一个Student对象
stu.read(); // 调用对象的方法
}
}
class Student1 {
String 姓名;
public void read(){
姓名 = "张三";
System.out.println(姓名+"正在看书。");
}
}
package cn.zxx.ch03.ex00;
public class Example2_jxp {
public static void main(String[] args) {
System.out.println("【例题】局部变量与成员变量同名,方法中通过变量名访问到的是局部变量 (张晓轩)");
Student2 stu = new Student2(); // 创建第一个Student对象
stu.read(); // 调用对象的方法
}
}
class Student2 {
int 年龄 = 30;
public void read(){
int 年龄 = 50;
System.out.println("大家好,我" +年龄+"岁了,我在看书!");
}
}
2.2 对象的创建与使用
// 声明对象1
类名 对象名称 = null;
// 声明对象2
类名 对象名称;
// 创建对象
对象名称 = new 类名();
// 声明并创建对象
类名 对象名称 = new 类名();
Java把内存划分成两种: 一种是栈内存,一种是堆内存。
- 栈(Stack): 主要用于存储局部变量和对象的引用变量,每个线程都会有一个独立的栈空间,所以线程之间是不共享数据的。
---- 在方法(函数)中定义的一些基本类型的变量和对象的引用变量都在方法(函)数的栈内存中分配。
---- 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。 - 堆(heap): 主要用于存储实例化的对象,数组。由JVM动态分配内存空间。一个JVM只有一个堆内存,线程是可以共享数据的。
---- 堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。
package cn.zxx.ch03.ex01;
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例题01】对象的创建与使用 (张晓轩)");
Student stu1 = new Student(); // 创建第一个Student对象
Student stu2 = new Student(); // 创建第二个Student对象
stu1.姓名 = "小明"; // 为stu1对象的 姓名 属性赋值
stu1.年龄 = 18;
stu1.read(); // 调用对象的方法
stu2.姓名 = "张晓轩";
stu2.年龄 = 60;
stu2.read();
}
}
class Student {
String 姓名; // 声明姓名属性
int 年龄; // 声明年龄属性
void read() {
System.out.println("大家好,我是" + 姓名 +",年龄" + 年龄);
}
}
2.3 对象的引用传递
类属于引用数据类型,引用数据类型就是指内存空间可以同时被多个栈内存引用。
package cn.zxx.ch03.ex02;
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例02】对象的引用传递 (张晓轩)");
Student stu1 = new Student(); //创建stu1对象并实例化stu1.
stu1.name ="张三";
stu1.age = 18;
stu1.read();
System.out.println(" -----stu2 = stu1; 之后-------- ");
Student stu2= null; //创建stu2对象,但不对其进行实例化建stu2对象,但不对其进行实例化
stu2 = stu1; //把对象stu1赋给对象stu2, 即 stu2引用stu1----stu1和stu2同时指向同一堆内存
stu2.name ="张晓轩";
stu2.age = 60;
stu1.read();
stu2.read();
}
}
class Student {
String name; // 声明姓名属性
int age; // 声明年龄属性
void read() {
System.out.println("大家好,我是" + name + ",年龄" + age);
}
}
注意:一个栈内存空间只能指向一个堆内存空间,如果想要再指向其他堆内存空间,就必须先断开已有的指向才能分配新的指向。
2.4 访问控制权限
在Java中,针对类、成员方法和属性,Java提供了4种访问控制权限,分别是private、default、protected和public。
访问控制权限的访问范
访问范围 | private(私有) | default(缺省、默认) | protected(受保护) | public(公开) |
---|---|---|---|---|
同一类中 | √ | √ | √ | √ |
同一包中的类 | √ | √ | √ | |
不同包的子类 | √ | √ | ||
全局范围 | √ |
(1) 同一类中
package cn.zxx.ch03.ex02_;
public class Student {
private int 年龄 = 16; //私有的
int 体重 = 56; //默认的
protected String 住址 = "文华街125号"; //受保护的
public String 姓名 = "张晓轩"; //公共的
// 本类中可以访问 private、缺省/默认、protected、public的成员属性、成员方法
public void show() {
System.out.println("--- public修饰的方法中 ---");
System.out.println("年龄="+年龄);
System.out.println("体重="+体重);
System.out.println("住址="+住址);
System.out.println("姓名="+姓名);
}
void info() {
System.out.println("--- 缺省/默认方法中 ---");
System.out.println(" 年龄 = "+年龄);
System.out.println(" 体重 = "+体重);
System.out.println(" 住址 = "+住址);
System.out.println(" 姓名 = "+姓名);
}
protected void info2() {
System.out.println("--- protected修饰的方法中 ---");
System.out.println(" 年龄 = "+年龄);
System.out.println(" 体重 = "+体重);
System.out.println(" 住址 = "+住址);
System.out.println(" 姓名 = "+姓名);
}
private void me() {
System.out.println("--- private修饰的方法中 ---");
System.out.println("me 年龄 = "+年龄);
System.out.println("me 体重 = "+体重);
System.out.println("me 住址 = "+住址);
System.out.println("me 姓名 = "+姓名);
}
public static void main(String[] args) {
System.out.println("【例】访问控制权限 ---- 同一类中 (张晓轩)");
Student stu = new Student();
stu.show(); // public
stu.info(); // 缺省
stu.info2(); // protected
stu.me(); // private
System.out.println(stu.姓名); // public
System.out.println(stu.住址); // protected
System.out.println(stu.体重); // 默认
System.out.println(stu.年龄); // private
}
}
(2) 同一包下的其他类
package cn.zxx.ch03.ex02_;
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例题】访问修饰符--同一包下的其他类 (张晓轩)");
Student stu = new Student();
stu.show(); // public
stu.info(); // 缺省
stu.info2(); // protected
//stu.me(); // private me()' 在 'cn.jxp.ch03.ex02_.Student' 中具有 private 访问权
System.out.println(stu.姓名); // public
System.out.println(stu.住址); // protected
System.out.println(stu.体重); // 默认
// System.out.println(stu.年龄); // '年龄' 在 'cn.jxp.ch03.ex02_.Student' 中具有 private 访问权限
System.out.println(stu.姓名); // public
}
}
(3) 不同包下的其他类
package cn.zxx.ch03.ex02__;
import cn.jxp.ch03.ex02_.Student;
/**
* 1. private --私有的,只能在本类中访问
* 2. 缺省 default --默认的,只能在本包中访问
* 3. protected --除了本包可以使用外,在其他包的子类里可以访问
* 4.public --任意包,任意类
* 注意点:
* 1.局部变量是没有访问权限的
* 2. private还可以修饰类内部类--外部类有两种修饰public和默认
**/
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例题】访问修饰符--不同包下的其他类 (张晓轩)");
// 在其他包的其他类中,只有public修饰的才可以被访问到!
Student stu = new Student(); stu.show(); // public
//stu.info(); // 缺省 'info() 在cn.jxp.ch03.ex02_.Student 中不为 public。无法从外部软件包访问
//stu.info2(); // protected info2() 在cn.jxp.ch03.ex02_.Student 中具有 protected 访问权限
//stu.me(); // private me()' 在 'cn.jxp.ch03.ex02_.Student' 中具有 private 访问权
stu.show();
// stu.info(); // info()' 在 'cn.jxp.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
System.out.println(stu.姓名);
//System.out.println(stu.年龄); //'年龄' 在 'cn.jxp.ch03.ex02_.Student' 中具有 private 访问权限
//System.out.println(stu.体重); //'体重' 在 'cn.jxp.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
//System.out.println(stu.住址); //'住址' 在 'cn.jxp.ch03.ex02_.Student' 中具有 protected 访问权限
}
}package cn.zxx.ch03.ex02__;
import cn.jxp.ch03.ex02_.Student;
/**
* 1. private --私有的,只能在本类中访问
* 2. 缺省 default --默认的,只能在本包中访问
* 3. protected --除了本包可以使用外,在其他包的子类里可以访问
* 4. public --任意包,任意类
* 注意点:
* 1. 局部变量是没有访问权限的修饰
* 2. private还可以修饰类内部类--外部类有两种修饰public和默认
**/
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例题】访问修饰符--不同包下的其他类 (张晓轩)");
// 在其他包的其他类中,只有public修饰的才可以被访问到!
Student stu = new Student(); stu.show(); // public
//stu.info(); // 缺省 'info() 在cn.jxp.ch03.ex02_.Student 中不为 public。无法从外部软件包访问
//stu.info2(); // protected info2() 在cn.jxp.ch03.ex02_.Student 中具有 protected 访问权限
//stu.me(); // private me()' 在 'cn.jxp.ch03.ex02_.Student' 中具有 private 访问权
stu.show();
// stu.info(); // info()' 在 'cn.jxp.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
System.out.println(stu.姓名);
//System.out.println(stu.年龄); //'年龄' 在 'cn.jxp.ch03.ex02_.Student' 中具有 private 访问权限
//System.out.println(stu.体重); //'体重' 在 'cn.jxp.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
//System.out.println(stu.住址); //'住址' 在 'cn.jxp.ch03.ex02_.Student' 中具有 protected 访问权限
}
}
(4) 不同包下的其他类----包下的子包
package cn.zxx.ch03.ex02_.sub;
import cn.jxp.ch03.ex02_.Student;
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例题】访问修饰符--不同包(含子包)下的其他类 (张晓轩)");
// 在其他包(含子包)的其他类中,只有public修饰的才可以被访问到!
Student stu = new Student();
stu.show();
// stu.info(); // info()' 在 'cn.jxp.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
System.out.println(stu.姓名);
//System.out.println(stu.年龄); //'年龄' 在 'cn.jxp.ch03.ex02_.Student' 中具有 private 访问权限
//System.out.println(stu.体重); //'体重' 在 'cn.jxp.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
//System.out.println(stu.住址); //'住址' 在 'cn.jxp.ch03.ex02_.Student' 中具有 protected 访问权限
}
}
(5) 子类
package cn.zxx.ch03.ex02__;
import cn.jxp.ch03.ex02_.Student;
public class XiaoMing extends Student {
public static void main(String[] args) {
System.out.println("【例题】访问修饰符--子类中可访问protected/public修饰符的属性和方法 (张晓轩)");
XiaoMing xm = new XiaoMing();
// xm.info(); //info()' 在 'cn.jxp.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
// xm.me(); //'me()' 在 'cn.jxp.ch03.ex02_.Student' 中具有 private 访问权限
xm.show();
xm.info2();
System.out.println(xm.姓名);
System.out.println(xm.住址);
// System.out.println(xm.年龄); // '年龄' 在 'cn.jxp.ch03.ex02_.Student' 中具有 private 访问权限
// System.out.println(xm.体重); // '体重' 在 'cn.jxp.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
}
}
访问控制权限使用注意点
package cn.zxx.ch03.ex02__;
/**
* 注意点:
* 1. 局部变量是没有访问权限的,局部变量只在其作用域内起作用,不可能被其他类访问到
* 2. private还可以修饰类内部类,内部类可用4种修饰:public、默认、protected、private
* 3. 外部类只有两种修饰:public和默认
**/
public class Test {
void cc() { //默认访问权限,能在本包范围内使用
public int aa; //错误,局部变量没有访问权限控制
protected boolean bb; //错误,局部变量没有访问权限控制
System.out.println("包访问权限");
}
//private权限的内部类,即这是私有的内部类,只能在本类使用
private class InnerClass {
}
protected class InnerClass2 {
}
class InnerClass3 {
}
public class InnerClass4 {
}
}
private class Class2 {
}
protected class Class3 {
}
Java程序的文件名
- 如果一个Java源文件中定义的所有类都没有使用public修饰,那么这个Java源文件的文件名可以是一切合法的文件名;
- 如果一个源文件中定义了一个public修饰的类,那么这个源文件的文件名必须与public修饰的类名相同。
- 如果一个源文件中定义了一个以上public修饰的类,那么这个源文件的内容必定报错。
3. 封装性
封装是面向对象思想中的三个非常重要的概念(封装、继承、多态)之一。
3.1 为什么要封装
在Java面向对象的思想中,封装是指一种将类的实现细节包装、隐藏起来的方法。封装可以被认为是一个保护屏障,防止本类的代码和数据被外部类定义的代码随机访问。
package cn.zxx.ch03.ex03;
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例03】未封装 -- 成员变量(属性)没有修饰,类外部随意访问和修改 (张晓轩)");
Student stu = new Student(); // 创建学生对象
stu.name = "张三"; // 为对象的name属性赋值
stu.age = -18; // 为对象的age属性赋值,年龄负数
stu.read(); // 调用对象的方法
}
}
class Student {
String name; // 声明姓名属性
int age; // 声明年龄属性
void read() {
System.out.println("大家好,我是" + name + ",年龄" + age);
}
}
3.2 如何实现封装
类的封装是指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过该类提供的方法实现对内部信息的操作访问。
类的封装 = private属性 + public getter/setter
package cn.zxx.ch03.ex04;
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例04】封装:private属性+public setter/getter (张晓轩)");
Student stu = new Student(); // 创建学生对象
stu.set姓名("张晓轩"); // 为对象的name属性赋值
stu.set年龄(-60); // 为对象的age属性赋值
stu.read(); // 调用对象的方法
System.out.println(stu.toString());
}
}
class Student{
private String 姓名; // 声明姓名属性
private int 年龄; // 声明年龄属性
public String get姓名() {
return 姓名;
}
public void set姓名(String 姓名) {
this.姓名 = 姓名;
}
public int get年龄() {
return 年龄;
}
public void set年龄(int 年龄) {
if(年龄 < 0){
System.out.println("您输入的年龄有误!");
} else {
this.年龄 = 年龄;
}
}
@Override
public String toString() {
return "Student{" +
"姓名='" + 姓名 + '\'' +
", 年龄=" + 年龄 +
'}';
}
public void read() {
System.out.println("大家好,我是"+姓名+",年龄"+年龄);
}
}
4. 构造方法
4.1 定义构造方法
构造方法是一个特殊的成员方法。
- (1)构造方法的名称必须与类名一致,且public公开的。
- (2)构造方法名称前不能有任何返回值类型的声明。
- (3)不能在构造方法中使用return返回一个值,但可以单独写return语句作为方法的结束。
package cn.zxx.ch03.ex05;
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例05】无参构造方法 (张晓轩)");
System.out.println("声明对象...");
Student stu = null; //声明对象
System.out.println("实例化对象...");
stu = new Student(); //实例化对象
}
}
class Student {
public Student() {
System.out.println(" 调用了无参构造方法");
}
}
package cn.zxx.ch03.ex06;
class Student{
private String 姓名;
private int 年龄;
public Student(String n, int a) {
姓名 = n;
年龄 = a;
System.out.println("调用了有参构造方法");
}
public void read(){
System.out.println(" 我是:"+姓名+",年龄:"+年龄);
}
}
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例06】有参构造方法 (张晓轩)");
Student stu = new Student("张晓轩",18); // 实例化Student对象
stu.read();
}
}
4.2 构造方法的重载
与普通方法一样,构造方法也可以重载,在一个类中可以定义多个构造方法,但是需要每个构造方法的参数类型、参数个数或类型顺序不同。
package cn.zxx.ch03.ex07;
class Student{
private String 姓名;
private int 年龄;
public Student() {
System.out.println("调用了无参数的构造方法");
}
public Student(String n) {
姓名 = n;
System.out.println("调用了一个参数的构造方法");
}
public Student(String n,int a) {
姓名 = n;
年龄 = a;
System.out.println("调用了两个参数的构造方法");
}
public void read(){
System.out.println(" 我是:"+姓名+",年龄:"+年龄);
}
}
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例07】构造方法重载 (张晓轩)");
Student stu1 = new Student("张三");
Student stu2 = new Student("李四",18); // 实例化Student对象
stu1.read();
stu2.read();
}
}
4.3 默认构造方法
在Java中的每个类都至少有一个构造方法,如果在一个类中没有定义构造方法,编译系统会自动为这个类创建一个默认的构造方法,这个默认的构造方法没有参数,方法体中没有任何代码,所以Java中默认的构造方法在程序运行时什么也不做。
// 第一种写法
class Student {
}
// 第二种写法:
class Student {
public Student(){
}
}
// 两种写法,效果是完全一样的。
由于系统提供的默认构造方法往往不能满足需求,因此,通常需要程序员自己在类中定义构造方法。
一旦为类定义了构造方法,系统就不再提供默认的构造方法。
一旦为类定义了有参构造方法,系统就不再提供默认的构造方法,此时调用 new 类名() 就会出错。
package cn.zxx.ch03.ex08;
class Student{
int age;
public Student(int n) {
age = n;
}
}
public class Example_jxp {
public static void main(String[] args) {
Student stu1 = new Student(18);
Student stu2 = new Student(); //应为 1 个实参,但实际为 0 个
}
}
注意:
- 为了避免上面的错误,在一个类中如果定义了有参的构造方法,最好再定义一个无参的构造方法。
- 构造方法通常使用public进行修饰。
5. this关键字
5.1 使用this关键字调用本类中的属性
在实际开发中,如果成员变量和局部变量的名称设置成一样的,会导致成员变量和局部变量的名称冲突。
package cn.zxx.ch03.ex09;
class Student {
private String name;
private int age;
// 定义构造方法
public Student(String name,int age) {
name = name;
age = age;
}
public String read(){
return "我是:"+name+",年龄:"+age;
}
}
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例09】成员变量和局部变量同名冲突 (张晓轩)");
Student stu = new Student("张三", 18);
System.out.println(stu.read());
}
}
package cn.zxx.ch03.ex10;
class Student {
private String name;
private int age;
// 定义构造方法
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public String read(){
return "我是:"+name+",年龄:"+age;
}
}
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例10】this解决成员变量和局部变量同名冲突 (张晓轩)");
Student stu = new Student("张三", 18);
System.out.println(stu.read());
}
}
5.2 使用this关键字调用成员方法
class Student {
public void openMouth() {
...
}
public void read() {
this.openMouth();
// 注意的是此处的this关键字也可以省略不写。
// openMouth();
}
}
5.3 使用this关键字调用构造方法
构造方法是在实例化对象时被Java虚拟机自动调用,在程序中不能像调用其他成员方法一样调用构造方法,但可以在一个构造方法中使用“this(参数1,参数2…)”的形式调用其他的构造方法。
package cn.zxx.ch03.ex11;
class Student {
private String name;
private int age;
public Student () {
System.out.println("调用了无参的构造方法");
}
public Student (String name,int age) {
this(); // 调用无参的构造方法
this.name = name;
this.age = age;
}
public String read(){
return "我是:"+name+",年龄:"+age;
}
}
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例11】使用this关键字调用构造方法 (张晓轩)");
Student stu = new Student("张三",18); // 实例化 Student对象
System.out.println(stu.read());
}
}
this调用类的构造方法时,注意三点
- 只能在构造方法中使用this调用其他的构造方法,不能在成员方法中通过this调用构造方法。
- 在构造方法中,使用this调用其他构造方法的语句必须位于第一行,且只能出现一次。
- 不能在一个类的两个构造方法中使用this互相调用
class Student {
public Student () {
this("张三"); // 调用有参构造方法
System.out.println("无参的构造方法被调用了。");
}
public Student (String name) {
this(); // 调用无参构造方法
System.out.println("有参的构造方法被调用了。");
}
}
JavaBean ---- java咖啡豆
一种特殊的Java类,一种编程规范。
- public class 类名
- private 属性s
- public getter、setter
- 无参构造方法
代码编辑区点击鼠标右键,生成getter和setter等代码。
6. 代码块
代码块可以分为4种:普通代码块、构造块、静态代码块、同步代码块。本小节将针对普通代码块和构造块进行讲解。静态代码块将在下一小节的static关键字中进行讲解,同步代码块将在多线程部分进行讲解。
6.1 普通代码块
普通代码块就是直接在方法或是语句中定义的代码块
package cn.zxx.ch03.ex12;
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例12】普通代码块--方法中的代码块 (张晓轩)");
{
int age = 18;
System.out.println("这是普通代码块。age:"+age);
}
int age = 30;
System.out.println("age:"+age);
}
}
6.2 构造块
构造代码块是直接在类中定义的代码块。
package cn.zxx.ch03.ex12_;
class Student{
String name; //成员属性
{
System.out.println("我是构造代码块----直接定义在类中的代码块"); //与构造方法同级
}
//构造方法
public Student(){
System.out.println("我是Student类的构造方法");
}
{
System.out.println("我是构造代码块2----直接定义在类中的代码块"); //与构造方法同级
}
}
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例12_】构造代码块--直接在类中定义的代码块 (张晓轩)");
Student stu1 = new Student();
Student stu2 = new Student();
}
}
两点结论
- (1)构造块的执行顺序早于构造方法(这里和构造块写在前面还是后面没有关系)。
- (2)每当实例化一个类对象(new 类名([...])),都会在执行构造方法之前执行构造块
7. static关键字
7.1 静态属性
package cn.zxx.ch03.ex13;
class Student {
String 姓名; // 定义name属性
int 年龄; // 定义age属性
String 所在大学 = "华北工学院"; // 假设我们本系统中 所有的学生都是同一所大学:华北工学院
public Student(String 姓名,int 年龄){
this.姓名 = 姓名;
this.年龄 = 年龄;
}
public void info(){
System.out.println("姓名:" + this.姓名+",年龄:" +this.年龄+
",所在大学:" + 所在大学);
}
}
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例13】所在大学 属性具有所有同学的共同属性 (张晓轩)");
Student stu1 = new Student("张三",18); // 创建学生对象
Student stu2 = new Student("李四",19);
Student stu3 = new Student("王五",20);
stu1.info();
stu2.info();
stu3.info();
//修改stu1对象的school的值
stu1.所在大学 = "中北大学";
System.out.println("修改stu1学生对象的学生信息为中北大学后");
stu1.info();
stu2.info();
stu3.info();
}
}
静态属性访问格式
如果在Java程序中使用static修饰属性,则该属性称为静态属性(也称全局属性----所有成员共同的属性)。
类名.静态属性名
或
实例对象名.静态属性名
package cn.zxx.ch03.ex14;
class Student {
String 姓名; // 定义name属性
int 年龄; // 定义age属性
static String 所在大学 = "华北工学院"; // 假设我们本系统中 所有的学生都是同一所大学:华北工学院
public Student(String 姓名,int 年龄){
this.姓名 = 姓名;
this.年龄 = 年龄;
}
public void info(){
System.out.println("姓名:" + this.姓名+",年龄:" +this.年龄+
",所在大学:" + 所在大学);
}
}
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例14】static 所有成员的共同属性 (张晓轩)");
Student stu1 = new Student("张三",18); // 创建学生对象
Student stu2 = new Student("李四",19);
Student stu3 = new Student("王五",20);
stu1.info();
stu2.info();
stu3.info();
//修改stu1对象的school的值
stu1.所在大学 = "中北大学";
System.out.println("修改stu1学生对象的学生信息为中北大学后");
stu1.info();
stu2.info();
stu3.info();
System.out.println("所有学生共同具备的属性 所在大学="+ Student.所在大学);
}
}
static关键字只能修饰成员变量,不能修饰局部变量,否则编译器会报错。
7.2 静态方法
在实际开发时,开发人员有时希望编写所有成员共同一致的方法(静态方法),这时就需要使用静态方法,要实现静态方法只需要在成员方法前加上static关键字。静态方法也可以通过类名和对象访问
类名.静态方法名(...)
或
实例对象名.静态方法名(...)
package cn.zxx.ch03.ex15;
class Student {
String 姓名; // 定义name属性
int 年龄; // 定义age属性
private static String 所在大学 = "华北工学院"; // 假设我们本系统中 所有的学生都是同一所大学:华北工学院
public Student(String 姓名,int 年龄){
this.姓名 = 姓名;
this.年龄 = 年龄;
}
public void info(){
System.out.println("姓名:" + this.姓名+",年龄:" +this.年龄+
",所在大学:" + 所在大学);
}
public static String get所在大学() {
return 所在大学;
}
public static void set所在大学(String s) {
所在大学 = s;
}
}
public class Example_jxp {
public static void main(String[] args) {
System.out.println("【例15】static 所有成员的共同方法 (张晓轩)");
Student stu1 = new Student("张三",18); // 创建学生对象
Student stu2 = new Student("李四",19);
Student stu3 = new Student("王五",20);
stu1.info();
stu2.info();
stu3.info();
//修改stu1对象的school的值
Student.set所在大学("中北大学");
//stu1.set所在大学("中北大学");
System.out.println("修改Student 所在大学:为中北大学后");
stu1.info();
stu2.info();
stu3.info();
System.out.println("所有学生共同具备的属性 所在大学="+ Student.get所在大学());
}
}
注意:静态方法只能访问静态成员,因为非静态成员需要先创建对象才能访问,即随着对象的创建,非静态成员才会分配内存。而静态方法在被调用时可以不创建任何对象。
7.3 静态代码块
在Java类中,用static关键字修饰的代码块称为静态代码块。当类被加载时,静态代码块就会执行,由于类只加载一次,所以静态代码块只执行一次。在程序中,通常使用静态代码块对类的成员变量进行初始化。
package cn.zxx.ch03.ex16;
class Student{
String name; //成员属性
{
System.out.println("我是构造代码块");
}
static {
System.out.println("我是静态代码块");
}
public Student(){ //构造方法
System.out.println("我是Student类的构造方法");
}
{
System.out.println("我是构造代码块2");
}
static {
System.out.println("我是静态代码块2");
}
}
class Example_jxp{
public static void main(String[] args) {
System.out.println("【例16】static代码块 -- 只执行一次 (张晓轩)");
Student stu1 = new Student();
System.out.println("-----");
Student stu2 = new Student();
System.out.println();
Student stu3 = new Student();
}
}