文章目录
- 面向对象思想
- 概述
- 面向过程与面向对象的区别
- 举例
- 区别
- 代码展示
- 特点
- 面向对象三条主线
- 类和对象
- 什么是类
- 什么是对象
- 类与对象的关系
- 类的定义
- 事物与类的对比
- 类的定义格式
- 对象的使用
- 使用步骤
- 代码举例
- 例一
- 例二
- 成员变量默认值
- 对象内存图
- `jvm`内存划分图
- 一个对象的内存图
- 两个对象引用指向不同对象空间的内存图
- 两个对象引用指向同一对象空间的内存图
- 对象在方法中的使用
- 使用对象类型作为方法的参数
- 使用对象类型作为方法的返回值
- 成员变量和局部变量的区别
- 练习
- 方法
- 方法重载
- 概念
- 特点
- 可变形参的方法
- 格式
- 使用
- **方法参数的值传递机制**
- 练习
- 练习1
- 练习2
- 递归方法
- 三大特征之封装
- 封装概述
- 概述
- 原则
- 体现
- private关键字
- 使用说明
- 间接访问
- Setter方法
- Getter方法
- 练习
- this关键字
- **谁调用的方法,this就指向谁。**
- this 调用构造器
- 构造器
- 构造器的定义格式
- 注意事项
- 标准代码——JavaBean
- 举例
- static
- 修饰属性
- 使用场景
- static内存图
- 修饰方法
- 使用场景
- 修饰代码块
- 静态代码块
面向对象思想
概述
Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,使用Java语言去设计、开发计算机程序。 这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。 它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。
面向过程与面向对象的区别
面向过程:当需要实现一个功能时,每一个具体的步骤都要亲历亲为,详细处理每一个细节。
面向对象:当需要实现一个功能时,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我们做事。
举例
洗衣服:
面向过程:把衣服脱下来–>找一个盆–>放点洗衣粉–>加点水–>浸泡10分钟–>揉一揉–>清洗衣服–>拧干–>晾起来
面向对象:把衣服脱下来–>打开全自动洗衣机–>扔衣服–>按钮–>晾起来
区别
面向过程:强调步骤。
面向对象:强调对象,这里的对象就是洗衣机。
代码展示
public class Demo01PrintArray {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
// 要求打印格式为:[1, 2, 3, 4, 5]
// 面向过程实现
System.out.print("[");
for(int i = 0; i < arr.length; i++){
if(i < arr.length - 1) {
System.out.print(arr[i] + ", ");
} else {
System.out.println(arr[i] + "]");
} // 需要关注功能实现的每一个细节
}
System.out.println("===============");
// 面向对象实现
System.out.println(Arrays.(arr));
// 不需要关注功能实现的每一个细节,只需要调用具有这个功能的方法即可。
//Arrays.toString()
//JDK提供的Arrays类中的toString() 方法
//Arrays.toString() 可以将数组转换成字符串格式
}
}
特点
面向对象思想是一种更符合我们思考习惯的思想,它可以将复杂的事情简单化,并将我们从执行者变成了指挥者。面向对象的语言中,包含了三大基本特征,即封装、继承和多态。
面向对象三条主线
- 类及类的成员:属性(成员变量)、成员方法、构造器、代码块、内部类。
- 面向对象三大特性:封装、继承、多态。
- 其它关键字:this, super, abstract, interface, final, package, import…
类和对象
什么是类
类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。
现实中,描述一类事物:
属性:就是该事物的状态信息。
行为:就是该事物能够做什么。
举例:小猫。
属性:名字、体重、年龄、颜色。
行为:走、跑、叫。
什么是对象
对象:是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为。
现实中,一类事物的一个实例:一只小猫。
举例:一只小猫。
属性:tom、5kg、2 years、yellow。
行为:溜墙根走、蹦跶的跑、喵喵叫。
类与对象的关系
类是对一类事物的描述,是抽象的。
对象是一类事物的实例,是具体的。
类是对象的模板,对象是类的实体。
类的定义
事物与类的对比
-
现实世界的一类事物:
属性:事物的状态信息。
行为:事物能够做什么。
-
Java中用class描述事物也是如此:
成员变量:对应事物的属性
成员方法:对应事物的行为
类的定义格式
public class ClassName {
//成员变量
//成员方法
}
定义类:就是定义类的成员,包括成员变量和成员方法。
成员变量:和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外,也叫类的属性,field。
成员方法:和以前定义方法几乎是一样的。只不过把static去掉,static的作用在面向对象后面课程中再详细讲解。
/*
定义一个类,用来模拟"学生",其中就有两个组成部分:
1、属性(是什么):
姓名、年龄、性别、...
2、行为(能做什么):
吃饭、睡觉、学习、...
对应到java的类当中:
1、成员变量(属性):
String name; // 姓名
int age; // 年龄
byte sex; // 性别 0:女,1:男,2:保密
2、成员方法(行为):
public void eat() {} // 吃饭
public void sleep() {} // 睡觉
public void study() {} // 学习
*/
public class Student {
// 成员变量
String name; // 姓名
int age; // 年龄
byte sex; // 性别
// 成员方法
public void eat(){
System.out.println("吃!");
}
public void sleep() {
System.out.println("睡!");
}
public void study() {
System.out.println("学!");
}
}
对象的使用
使用步骤
通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用,具体分为以下三个步骤:
-
导包:指出需要使用的类在什么位置。
如果类同属于一个包中(同一路径下),可以省略导包语句。
// 导包语句
// import packageName.className;
import cn.study.day07.demo03.Demo02Student;
- 创建
// className objName = new className();
Student stu = new Student();
- 使用
使用成员变量
// objName.memberVarName
stu.name = "张三";
使用成员方法
// objName.memberMethName(para,...) para可以是0或多个
stu.eat();
总结:想用谁,就用对象名点儿谁。
代码举例
例一
public class Demo02Student {
public static void main(String[] arg){
// 1. 导包
// 需要使用的Student类,和当前所在类同属一个包下,可以省略导包语句。
// 2. 创建
// className objName = new className();
Student stu = new Student();
// 根据Student类创建了一个stu的对象。
//3. 使用其中的成员变量
System.out.println(stu.name); // null
System.out.println(stu.age); // 0
System.out.println(stu.sex); // '\u0000'
// Student类中没有给成员变量赋值
// 默认值与数组的规则相同
System.out.println("=====================");
// 改变对象当中的成员变量内容
stu.name = "张三";
stu.age = 18;
stu.sex = '男';
System.out.println(stu.name); // 张三
System.out.println(stu.age); // 18
System.out.println(stu.sex); // 男
System.out.println("=====================");
// 使用成员方法
stu.eat();
stu.sleep();
stu.study();
}
}
例二
/*
定义一个类,用来模拟"手机"事物
属性:品牌、价格、颜色...
行为:通话、短信...
对应到类当中:
成员变量(属性)
String brand;
double price;
String color;
成员方法(行为)
public void call(String who) {} // 打电话
public void sendMessage() {} // 群发短信
*/
public class Phone {
//成员变量
String brand; // 品牌
double price; // 价格
String color; // 颜色
//成员方法
public void call(String who){
System.out.println("给" + who + "打电话");
}
public void sendMessage() {
System.out.println("群发短信");
}
}
public class Demo03PhoneOne {
public static void main(String[] args) {
// 根据Phone类,创建一个名为one的对象;
Phone one = new Phone();
System.out.println(one.brand); // null
System.out.println(one.price); // 0.0
System.out.println(one.color); // null
System.out.println("===================");
// 给对象当中的成员重新赋值
one.brand = "小米";
one.price = 998.0;
one.color = "黑色";
System.out.println(one.brand); // 小米
System.out.println(one.price); // 998.0
System.out.println(one.color); // 黑色
System.out.println("===================");
one.call("雷军");
one.sendMessage();
}
}
成员变量默认值
成员变量如果未赋值,将会有一个默认值,规则如下:
- 整数类型,默认为0;
- 浮点类型,默认为0.0;
- 字符类型,默认为
'\u0000'
; - 布尔类型,默认为
false
; - 引用类型,默认为
null
。
对象内存图
jvm
内存划分图
一个对象的内存图
堆中的成员变量是参考方法区.class中成员变量的信息创建的,其中的值就保存在堆(Heap)中。
堆中的成员方法保存的是一个地址值,指向了方法区中的成员方法信息。
进栈也叫压栈,先进栈的在后进栈的下面,后来的压着先来的。
出栈也叫弹栈,当方法执行完毕后会立刻从栈中销毁,main方法执行完毕,则程序结束。
先进后出,后进先出。
两个对象引用指向不同对象空间的内存图
对象名,也叫对象引用
从上图可以看到,两个对象在创建时,分别在堆区开辟了不同的内存空间,各自保存着本对象的成员变量和成员方法,但是这两块堆区内存空间同时指向了方法区里同一块空间。也就是它们的所具有的属性和功能是完全相同的,不同的是成员变量的值和成员方法调用的参数。
这会出现一个问题,每创建一个对象就需要在堆中开辟一块内存空间,但是里面保存的信息基本相同,因此十分浪费内存空间。
两个对象引用指向同一对象空间的内存图
对象在方法中的使用
使用对象类型作为方法的参数
任何数据类型都能作为方法的参数。
对象引用作为参数传递给方法的是对象的地址值。
public class Demo04PassObjParam {
public static void main(String[] args) {
Phone one = new Phone();
one.brand = "小米";
one.price = 998.0;
one.color = "土豪金";
mothod(one); // 传递的对象的地址
System.out.println(one);
}
public static void mothod(Phone param){
System.out.println(param);
System.out.println(param.brand); // 苹果
System.out.println(param.price); // 998.0
System.out.println(param.color); // 土豪金
}
}
使用对象类型作为方法的返回值
使用对象类型作为方法的返回值时,返回的是对象的地址值。
public class Demo05PhoneReturn {
public static void main(String[] args) {
// 用对象类型接收返回值
Phone two = getPhone();
System.out.println(two.brand); // 小米
System.out.println(two.price); // 799.0
System.out.println(two.color); // RoseGold
}
public static Phone getPhone() {
Phone one = new Phone();
one.brand = "小米";
one.price = 799.0;
one.color = "RoseGold";
return one;
}
}
成员变量和局部变量的区别
-
定义的位置不一样
局部变量:在方法的内部
成员变量:在方法的外部,直接写在类当中。
-
作用域不一样
局部变量:所在方法中可以使用,出了所在方法就不能使用。
成员变量:整个类全都可以通用。
-
默认值不一样
局部变量:没有默认值,要使用,必须先赋值。
成员变量:如果没有赋值,会有默认值,规则和数组一样。
-
内存的位置不一样
局部变量:位于栈内存。
成员变量:位于堆内存。
-
声明周期不一样
局部变量:随着方法进栈而创建,随着方法出栈而销毁。
成员变量:随着对象创建而创建,随着对象被垃圾回收而消失。
-
权限修饰符的使用不同,
public、 protected、 缺省、 private
局部变量:不能使用权限修饰符。
成员变量:可以使用权限修饰符。
public class Demo01VariableDifference {
String name; // 成员变量
public void methodA(){
int num = 20; // 局部变量
System.out.println(num);
}
public void methodB(int param) { //参数就是局部变量
// System.out.println(num); // 错误,num是methodA方法中的局部变量,不能在methodB中使用
System.out.println(name); // 成员变量,类中都可以使用
int age; // 局部变量
// System.out.println(age); // 局部变量未赋值不能使用
// 参数在方法调用时,必然会被赋值
System.out.println(param); // 这种写法没有问题
}
}
练习
创建一个学生类,三个属性,学号,年级和成绩。
创建20个学生类,其中学号从1开始到20结束,年级和成绩随机赋值。
Student类
// Student类
package cn.study.day26.demo05;
public class Student {
private int number = id; // 学号
private int state; // 年级
private int score; // 成绩
private static int id = 1; // 自增id
// 无参构造器
public Student() {
++id;
}
// 有参构造器,number和id变量自增,不允许设置
public Student(int state, int score) {
this.state = state;
this.score = score;
}
public String stuInfo() {
String info = "学号:" + this.getNumber() + ", 年级:" +this.getState() + ", 成绩:" + this.getScore();
return info;
}
// Getter/Setter
public int getNumber() {
return this.number;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
工具类
// 工具类
package cn.study.day26.demo05;
public class Utility {
// 遍历打印学生信息
/**
* @Description 遍历Student数组,并打印数组中学生对象的信息
* @author Joker
* @param stus 要遍历的数组
*/
public static void traverseStu(Student[] stus) {
for (int i = 0; i < stus.length; i++) {
System.out.println(stus[i].stuInfo());
}
}
/**
* @Description 筛选出Student数组中指定年级学的信息,并打印。
* @author Joker
* @param state 需要筛选出来的年级
*/
public static void searchStu(Student[] stus, int state) {
for (int i = 0; i < stus.length; i++) {
if (stus[i].getState() == state) {
System.out.println(stus[i].stuInfo());
}
}
}
/**
* @Description 使用冒泡排序算法,按照成绩属性给Student数组排序,从小到大。
* @author Joker
* @param stus 要排序的数组
*/
public static void bubbleSortStus(Student[] stus) {
for (int i = 0; i < stus.length - 1; i++) {
boolean flag = true;
for (int j = 0; j < stus.length - 1 - i; j++) {
if (stus[j].getScore() > stus[j + 1].getScore()) {
Student temp = stus[j];
stus[j] = stus[j + 1];
stus[j + 1] = temp;
flag = false;
}
}
if(flag){
break;
}
}
}
// 按年级快速排序
/**
* Description 使用快速排序算法,按照年级属性给Student数组排序,从小到大
* @author Joker
* @param stus 要排序的数组
*/
public static void sortStus(Student[] stus){
quickSort(stus, 0, stus.length - 1);
}
// 快速排序
private static void quickSort(Student[] stus, int low, int high) {
int pivot = low;
if(low < high) {
pivot = partition(stus, low, high);
quickSort(stus,low,pivot - 1);
quickSort(stus,pivot + 1, high);
}
}
// 确定基轴值位置
private static int partition(Student[] stus, int low, int high) {
int pivotKey = stus[low].getState();
while(low < high) {
while(low < high && stus[high].getState() >= pivotKey){
high--;
}
swap(stus,low,high);
while (low < high && stus[low].getState() <= pivotKey){
low++;
}
swap(stus,low,high);
}
return low;
}
// 交换两个对象引用
private static void swap(Student[] stus, int low, int high) {
Student temp = stus[low];
stus[low] = stus[high];
stus[high] = temp;
}
}
测试类
// 测试类
package cn.study.day26.demo05;
public class StudentTestDrive {
public static void main(String[] args) {
Student[] stus = new Student[20];
for (int i = 0; i < stus.length; i++) {
stus[i] = new Student();
// stata = [1,6]
// score = [0,100]
// 随机数计算公式[a,b]
// Math.random * (b - a + 1) * a;
int state = (int) (Math.random() * (6 - 1 + 1) + 1);
int score = (int) (Math.random() * (100 + 1));
stus[i].setState(state);
stus[i].setScore(score);
}
// 按年级筛选学生
System.out.println("==========按年级筛选==========");
Utility.searchStu(stus,3);
// 按成绩冒泡排序
System.out.println("==========按成绩排序==========");
Utility.bubbleSortStus(stus);
Utility.traverseStu(stus); // 遍历打印学生信息
// 按年级快速排序
System.out.println("==========按年级排序==========");
Utility.sortStus(stus);
Utility.traverseStu(stus); // 遍历打印学生信息
}
}
方法
方法重载
概念
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数、参数类型或者参数顺序不同即可。
特点
与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数、参数类型或参数顺序),调用时,可以根据传传递的实参类型、个数、顺序来调用对应的方法。
可变形参的方法
JavaSE5.0 中提供了VarArgs(variable number of arguments)
机制,允许直接定义和能多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参。
格式
权限修饰符 返回值类型 方法名(数据类型 ... 参数名) {}
使用
-
当调用可变个数形参的方法时,传入的参数个数可以是
0,1,2... 多个
-
但是传入的参数必须与形参中的类型保持一致。
-
可变个数形参的方法与本类中方法名相同,参数列表不同的方法构成重载。
-
可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。
-
可变个数形参在方法的形参中,必须声明在末尾。
-
因此可变个数形参在方法的形参中,最多只能声明一个。
public class MethodVarArgsTest {
public static void main(String[] args) {
MethodVarArgsTest test = new MethodVarArgsTest();
test.show(10); // 重载方法1
test.show("hello"); // 重载方法2
test.show("hello","abcdef","12345"); // 可变个数形参方法
test.show(); // 没有参数也可以调用可变形参方法
}
// 重载方法
public void show(int i){
System.out.println("重载方法1");
}
public void show(String s) {
System.out.println("重载方法2");
}
public void show(String ... str) {
System.out.println("可变个数形参方法");
// 使用时,把可变个数形参当作数组使用
for(int i = 0; i < str.length;i++) {
System.out.println(str[i]); // 当作数组用
}
}
// 相同类型的数组会与可变类型方法 不能构成重载,会发生冲突。
/*public void show(String[] strs) {
}*/
// 正确写法,必须声明在末尾
public void show(int i, String ... str) {
}
// 错误写法! Vararg parameter must be the last in the list
/*public void show(String ... str, int i) {
}*/
}
方法参数的值传递机制
在Java中方法的参数传递方式只有一种**值传递
**,即将实际参数值的副本传入方法内,而参数本身不受影响。
- 形参是基本数据类型:将实参基本数据类型变量的**
数据值
**传给形参。 - 形参是引用数据类型:将实参引用数据类型变量的**
地址值
**传给形参。
练习
练习1
下面代码的输出结果是?
class Value {
int i = 15;
}
public class TransferTest3 {
public static void main(String args[]) {
TransferTest3 test = new TransferTest3();
test.first();
}
public void first() {
int i = 5;
Value v = new Value();
v.i = 25;
second(v,i);
System.out.println(v.i); // 20 【传递的是地址值】
}
public void second(Value v,int i) {
// v = 25, i = 5
i = 0; // i = 0
v.i = 20; // v = 25
Value val = new Value();
v = val; // v = 15
System.out.println(v.i+" " + i); // 15 0
}
}
练习2
// 下面代码的输出结果
public class ArrayPrintTest {
int[] arr = new int[]{1,2,3};
System.out.println(arr); // 地址值
char[] arr1 = new char[]{'a','b','c'};
System.out.println(arr1); // abc
// println(char[]) 的重载方法,会遍历该char[] 并打印
}
递归方法
方法递归(recursion
)包含了一种隐式的循环,它会重复执行某段代码,但是这种重复执行无须序循环控制。
递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
/**
* 递归方法的使用
*/
public class Demo01Recursion {
public static void main(String[] args) {
// 递归计算1-100所有自然数的和
int n = 100;
int sum = getSum(n);
System.out.println(sum);
// 递归计算n!
System.out.println(getFact(10));
// 已知有一个数列 f(0) = 1, f(1) = 4, f(n+2) = 2 * f(n+1) + f(n), 求f(10) 的值
// f(n + 2) = 2 * f(n + 1) + f(n);
// f(10) = 2 * f(9) + f(8)
// f(n) = 2 * f(n - 1) + f(n - 2);
System.out.println(f(10));
// 求第n个斐波那契数
System.out.println(Fib(10));
}
// 求和
public static int getSum(int n){
if(n >= 1){
return n + getSum(n-1);
}
return 0;
}
// 求阶乘
public static int getFact(int n){
return n == 1? 1 : n * getFact(n-1);
}
// 求f(n)
public static int f(int n){
if(n == 0){
return 1;
} else if(n == 1) {
return 4;
} else {
return 2 * f(n - 1) + f(n - 2);
}
}
// Fibonacci
public static int Fib(int n){
return n <= 2 ? 1 : Fib(n - 1) + Fib(n - 2);
}
}
三大特征之封装
面向对象三大特征:封装、继承、多态。
封装概述
概述
面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。
封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。
程序设计追求:高内聚、低耦合。
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅对外暴露少量的方法用于使用。
原则
将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。
体现
- 方法就是一种封装。
- 关键字private也是一种封装。
public class Demo02Method {
public static void main(String[] args) {
int[] arr= {1,2,3,4,5};
int max = getMax(arr);
System.out.println("最大值" + max);
}
public static int getMax(int[] arr){
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
max = arr[i] > max ? arr[i] : max;
}
return max;
}
}
// 方法的调用者并不关心如何getMax()中的实现细节,它只是调用getMax()来完成获取数组最大值的功能。
// 将方法封装起来,就是隐藏细节,对外界不可见。
private关键字
private关键字用于修饰需要被保护的成员变量。
使用说明
// 创建一个Person 类
public class Person {
String name;
int age;
public void show(){
System.out.println("My name is " + name + ". I'm " + age + " years old");
}
}
// 在main方法中创建一个Person对象
public class Demo03Person {
public static void main(String[] args) {
Person person = new Person();
// 对对象中的成员变量进行赋值
person.name = "Joker";
person.age = -18; // -18 不合理的数值,成员变量无法阻止这个不合法的数据被设置。
person.show();
// private就是用来保护成员变量被赋予这种不合理数值的。
}
}
private
关键字用来修饰成员变量,被修饰的成员变量,在本类中可以随意访问,但是超出本类范围之外就不能在直接访问。
// 用private修饰 成员变量 age
public class Person {
String name;
private int age;
// 此时age 不能直接通过 对象名.成员变量名来访问
public void show(){
System.out.println("My name is " + name + ". I'm " + age + " years old");
}
}
如果想要访问private
修饰的成员变量,就需要使用间接访问的方法。
间接访问
间接访问private
修饰的成员变量,就是在本类中定义一对**Getter/Setter
方法**。
public class Person {
String name;
private int age;
public void show(){
System.out.println("My name is " + name + ". I'm " + age + " years old");
}
// Setter方法,专门用于设置age的数据
public void setAge(int num){
// 在Setter方法中加入判断条件,可以有效杜绝成员变量被赋予不合理的值。
if(num <= 150 && num >= 0){
age = num;
} else{
System.out.println("Error,the date of num is corrputed!");
}
}
// Getter方法,专门用获取age的数据
public int getAge() {
return age;
}
}
public class Demo03Person {
public static void main(String[] args) {
Person person = new Person();
person.name = "Joker";
// person.age = 18; // 此时需要访问age变量就不能使用直接访问的方法
person.setAge(18); // 而是使用间接访问的方法,并将想赋予的值写在方法调用()中
person.show();
int JokerAge = person.getAge(); // 获取成员变量的值,也应该使用间接访问方法
System.out.println("Joker's age is " + JokerAge);
}
}
Setter方法
public void setXxx(para) {
// 方法体
}
Setter方法必须有参数,无返回值;参数类型与要被设置的成员变量保持一致。
命名规则:set + 变量名首字母大写。
Getter方法
public dataType getXxx() {
// 方法体
}
Getter方法必须有返回值,无参数,返回值类型与要设置的成员变量保存一致。
命名规则:get + 变量名首字母大写。
练习
利用primate
关键字定义一个学生类
// 利用primate关键字定义一个学生类
public class Student {
private String name; // 姓名
private short age;
private boolean male; // true为男,false 为女
public void setName(String str){
name = str;
}
public String getName(){
return name;
}
public void setAge(short num){
age = num;
}
public short getAge() {
return age;
}
public void setMale(boolean b){
male = b;
}
// boolean的Getter方法命名 应该是 isXxxx
public boolean isMale() {
return male;
}
}
注意:
基本数据类型中的boolean
值,其Getter方法的命名一定要写成**isXxxx
**
// 使用学生类创建对象
public class Demo04Student {
public static void main(String[] args) {
Student stu = new Student();
stu.setName("张三");
stu.setAge(18);
stu.setMale(true);
System.out.println("姓名:" + stu.getName());
System.out.println("年龄:" + stu.getAge());
String sex = stu.isMale()? "男" : "女";
System.out.println("性别:" + sex);
}
}
this关键字
当成员方法中的局部变量,和成员变量重名时,根据"就近原则",优先使用局部变量。
// 定义Person类
public class Person {
String name; // 成员变量
// 成员方法的局部变量名和成员变量名都是name
public void sayHello(String name){ // 局部变量
System.out.println(name + ",您好!我是" + name);
}
}
// 使用Person类创建对象
public class Demo01Person {
public static void main(String[] args) {
Person person = new Person();
person.name = "张三";
person.sayHello("罗翔老师");
}
}
// 结果是成员方法优先使用的是局部变量name
解决方法是使用this关键字。
public class Person {
String name; // 姓名
public void sayHello(String name){
System.out.println(name + ",您好!我是" + this.name);
}
}
// this.name 就相当于 person.name
谁调用的方法,this就指向谁。
public class Person {
String name; // 姓名
public void sayHello(String name){
System.out.println(name + ",您好!我是" + this.name);
System.out.println(this); // 在成员方法中打印调用者的地址。
}
}
public class Demo01Person {
public static void main(String[] args) {
Person person = new Person();
person.name = "张三";
person.sayHello("罗翔老师");
System.out.println(person); // 打印对象名
// 创建不同的对象
System.out.println("========================");
Person person1 = new Person();
person1.name = "李四";
person1.sayHello("罗翔老师");
System.out.println(person1); // 打印对象名
}
}
this 调用构造器
- 在类的构造器中,可以显式的使用
this(形参列表)
的方式,调用本类中指定的其他构造器。 - 构造器中不能通过
this(形参列表)
的方式来自己调用自己。 - 同时构造器之间不可以构成环形调用关系,如果一个类中有n个构造器,则最多有
n-1
个构造器中可以使用this(形参列表);
- 规定:
this(形参列表)
必须声明在当前构造器的首行,也就是构造器内部最多只能声明一个this(形参列表)
。 - 补充(了解):如果没有显式的在构造器中指定调用哪一个构造器,那么默认会调用super(),用来在子类实例化时先加载父类的结构。
构造器
构造器(constructor
)是专门用来创建对象的一种结构,当一个对象被创建时候,构造器用来初始化该对象,给对象的成员变量赋初始值。当我们通过关键new来创建对象时,其实就是在调用构造器。
tips:无论你与否自定义构造器,所有的类都有构造器,因为Java自动提供了一个空参构造器,一旦自己定义了构造器,Java自动提供的默认无参数构造器就会失效。
构造器的定义格式
修饰符 构造器名(参数类型 参数名称,...){
// 方法体
}
// 构造器名与所在类名称完全一样!
注意事项
- 构造器的名称必须和所在的类名称完全一样,包括大小写也要一样。
- 构造器没有返回值类型,包括void。
- 构造器不能
return
一个具体的返回值。 - 如果没有自定义构造器,编译器会自动提供一个无参数构造器,格式如下:
public className() {} // 编译器默认提供的构造器
- 一旦定义了至少一个构造器,编译器提供的构造器将失效。
- 构造器可以进行重载,方法名相同,参数列表不同
// 定义一个类,在其中定义构造器
public class Student {
// 成员变量
String name;
int age;
// 构造器可以重载
// 无参构造器
public Student() { // 名字和类名完全一样
System.out.println("无参构造器执行!");
}
// 全参构造器
public Student(String name, int age) {
System.out.println("全参构造器执行!");
this.name = name;
this.age = age;
}
// Setter/Getter 方法
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}
// 使用类
public class Demo02Student {
public static void main(String[] args) {
// 构造器的调用通过new className();
Student stu = new Student(); // 调用无参构造器,方法重载
System.out.println("=============================");
Student stu1 = new Student("张三",18); // 调用有参构造器,并进行初始化,方法重载
System.out.println("姓名:" + stu1.getName() + " 年龄:" + stu1.age);
System.out.println("=============================");
// Setter方法用来对成员变量重新赋值
stu1.setName("法外狂徒");
stu1.setAge(19);
System.out.println("姓名:" + stu1.getName() + " 年龄:" + stu1.age);
}
}
标准代码——JavaBean
一个标准的类同时需要拥有下面四个组成部分:
- 所有的成员变量都要使用**
private
**关键字修饰。 - 为每一个成员编写一对**
Getter/Setter
**方法。 - 编写一个无参数的构造器。
- 编写一个全参数的构造器
这样一个标准的类也被称为 Java Bean
public class ClassName{
//成员变量
//构造器
//无参构造器【必须】
//有参构造器【建议】
//成员方法
//getXxx()
//setXxx()
}
举例
// 定义一个标准的学生类
public class Student {
// 成员变量
private String name; // 姓名
private int age; // 年龄
// 自动生成的无参构造器
public Student() {
}
// 自动生成的全参构造器
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 自动生成的Getter / Setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//使用类
public class Demo01Student {
public static void main(String[] args){
Student stu1 = new Student(); // 调用无参构造器
stu1.setName("张三"); // 使用Setter方法赋值
stu1.setAge(18);
// 使用Getter方法获取值
System.out.println("姓名:" + stu1.getName() + ",年龄:" + stu1.getAge());
System.out.println("====================");
Student stu2 = new Student("李四",19); // 调用全参构造器
System.out.println("姓名:" + stu2.getName() + ",年龄:" + stu2.getAge());
System.out.println("====================");
stu1.setName("法外狂徒"); // Setter方法修改值
stu1.setAge(99);
System.out.println("姓名:" + stu1.getName() + ",年龄:" + stu1.getAge());
}
}
static
static
主要修饰类的内部结构:属性、方法、代码块、内部类。
被static
修饰的内部结构,会随着类的加载而加载。
修饰属性
static修饰的属性,称作静态变量。
- 随着类的加载而加载。
- 在程序运行期间只会被加载一次。
- 属于类不属于对象。(权限运行,对象可以调用)
- 存在于方法的静态域中。
使用场景
- 当该属性可以被多个对象共享时。例如: 国籍、教室等公共的属性。
- 类中的常量,经常被
static
修饰。
static内存图
修饰方法
static修饰的方法,被称作静态方法。
- 随着类的加载而加载。
- 静态方法中,只能调用静态的方法或属性。
- 非静态方法中,既可以调用静态的方法或属性、也可以调用非静态的方法或属性。
- 在静态的方法内,不能使用
this
和super
关键字。
使用场景
- 方法中如果需要操作静态属性,同常设置为静态方法。
- 工具类中的方法,习惯上声明为
static
的。比如:Math、Arrays、Collections
修饰代码块
staitc修饰的代码块称为静态代码块。
静态代码块
- 内部可以有输出语句。
- 随着类的加载而执行。
- 只会在类加载的时候,执行唯一一次。
- 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行。
- 静态代码块内只能调用静态的属性。静态的方法,不能调用非静态的结构。
- 作用:初始化静态属性。