Java开发入门到精通 -- 面向对象概述与封装性

本篇主要介绍了Javak开发入门到精通 -- 面向对象概述与封装性,通过具体的内容展现,希望对Java开发的学习有一定的帮助。面向对象思想概述Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指。

本篇主要介绍了Javak开发入门到精通 -- 面向对象概述与封装性,通过具体的内容展现,希望对Java开发的学习有一定的帮助。

面向对象思想

概述

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) 机制,允许直接定义和能多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参。

格式

权限修饰符 返回值类型 方法名(数据类型 ... 参数名) {}

1

使用

当调用可变个数形参的方法时,传入的参数个数可以是 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修饰的代码块称为静态代码块。

静态代码块

内部可以有输出语句。

随着类的加载而执行。

只会在类加载的时候,执行唯一一次。

如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行。

静态代码块内只能调用静态的属性。静态的方法,不能调用非静态的结构。

作用:初始化静态属性。

我是小职,记得找我

✅ 解锁高薪工作

✅ 免费获取基础课程·答疑解惑·职业测评

Java开发入门到精通 -- 面向对象概述与封装性的介绍就聊到这里吧,感谢你花时间阅读,更多关于Java开发入门到精通 -- 面向对象概述与封装性的信息别忘了在本站进行查找哦。屹东网往后会继续推荐Java开发入门到精通 -- 面向对象概述与封装性相关内容。