1、初识面向对象
1.1、面向对象的两个要素
类:类是一个模板,它描述一类对象的行为和状态 ,是抽象的、概念上的定义。对象:是实际存在的该类事物的每个个体,因而也称为类实例(instance)。下图中汽车为类(class) ,而具体的每辆车为该汽车类的对象(object) ,对象包含了汽车的颜色、品牌、名称属性等。

面向对象程序设计的重点是类的设计。设计类,就是设计类的成员
- 属性 = 成员变量 =
field= 域、字段 - 方法 = 成员方法 = 函数 =
method - 创建类的对象 = 类的实例化 = 实例化类
Java里面,万事万物皆对象
1.2、面向对象基本使用
面向对象程序设计的基本流程:
- 创建类,设计类的成员
- 创建类的对象
- 通过
对象.属性或对象.方法调用对象的结构
如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的属性)意味着:如果我们修改一个对象的这个非static 的属性a,则不影响另外一个对象属性a的值。除非是引用传递(没有new创建新对象)
package com.lanmeix.java;
//测试类
public class PersonTest {
public static void main(String[] args) {
//2. 创建Person类的对象
Person p1 = new Person();
//Scanner scanner = new Scanner(System.in);
//调用对象的结构:属性、方法
//调用属性:“对象.属性”
p1.name = "Tom";
p1.isMale = true;
System.out.println(p1.name);
//调用方法:“对象.方法”
p1.eat();
p1.sleep();
p1.talk("Chinese");
//*******************************
Person p2 = new Person();
System.out.println(p2.name);//默认值null
System.out.println(p2.isMale);
//*******************************
//引用传递,将p1变量保存的对象地址值赋给p3,导致p1和p3指向了堆空间中的同一个对象实体。
Person p3 = p1;
System.out.println(p3.name);//Tom
p3.age = 10;
System.out.println(p1.age);//10
}
}
//1.创建类,设计类的成员
class Person{
//属性
String name;
int age = 1;
boolean isMale;
//方法
public void eat(){
System.out.println("人可以吃饭");
}
public void sleep(){
System.out.println("人可以睡觉");
}
public void talk(String language){
System.out.println("人可以说话,使用的是:" + language);
}
}
2、类中属性的使用
2.1、类中变量定义
一个类可以包含以下类型变量:
- 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
- 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
- 类变量:类变量也声明在类中,方法体之外,但必须声明为
static类型。该变量为多个对象所共享。
2.2、对象属性(成员变量) vs 局部变量
相同点:
- 定义变量的格式:数据类型 变量名 = 变量值
- 先声明,后使用
- 变量都有其对应的作用域
不同点:
| 成员变量 | 局部变量 | |
|---|---|---|
| 声明的位置 | 直接定义在类的一对{}内 | 声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量 |
| 权限修饰符 | private、public、缺省、protected | 不可以使用权限修饰符,可以使用 final 修饰 |
| 初始化值 | 根据其类型,都有默认初始化值 | 没有默认初始化值。意味着,我们在调用局部变量之前,一定要显式赋值。特别地:方法的形参在调用时,我们使用实参赋值即可。 |
| 内存加载位置 | 堆空间或静态域内 | 栈空间 |
实例演示
package com.lanmeix.java;
public class UserTest {
public static void main(String[] args) {
User u1 = new User();
System.out.println(u1.name);
System.out.println(u1.age);
System.out.println(u1.isMale);
u1.talk("韩语");
u1.eat();
}
}
class User{
//属性(或成员变量)
String name;
public int age;
boolean isMale;
public void talk(String language){//language:形参,也是局部变量
System.out.println("我们使用" + language + "进行交流");
}
public void eat(){
String food = "烙饼";//局部变量,必须要显示的赋值
System.out.println("北方人喜欢吃:" + food);
}
}
2.3、变量作用域
变量的范围是程序中该变量可以被引用的部分,方法内定义的变量被称为局部变量。
- 局部变量的作用范围从声明开始,直到包含它的块结束。
- 局部变量必须声明才可以使用。
- 方法的参数范围涵盖整个方法。参数实际上是一个局部变量。
for循环的初始化部分声明的变量,其作用范围在整个循环。但循环体内声明的变量其适用范围是从它声明到循环体结束。它包含如下所示的变量声明:
你可以在一个方法里,不同的非嵌套块中多次声明一个具有相同的名称局部变量,但你不能在嵌套块内两次声明局部变量。
3、类中方法的使用
3.1、set和get方法
在Java中,set方法和get方法通常用于类的属性的访问和修改。它们属于封装的范畴,是面向对象编程的核心概念之一。封装允许将对象的内部状态(即属性)隐藏起来,只通过公开的方法来对其进行访问。这不仅能保证数据的安全性,还能提高代码的可维护性。
get方法的作用是返回类的某个属性的值。通常,get方法的命名规则是:get+ 属性名(首字母大写)。set方法的作用是为类的属性赋值。通常,set方法的命名规则是:set+ 属性名(首字母大写)。
public class Person {
// 属性
private String name;
private int age;
private String sex;
// 空参构造器
public Person() {
}
// 全参构造器
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// Getter 和 Setter 方法
// 获取 name
public String getName() {
return name;
}
// 设置 name
public void setName(String name) {
this.name = name;
}
// 获取 age
public int getAge() {
return age;
}
// 设置 age
public void setAge(int age) {
this.age = age;
}
// 获取 sex
public String getSex() {
return sex;
}
// 设置 sex
public void setSex(String sex) {
this.sex = sex;
}
// 可以重写 toString() 方法来输出对象的属性
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
}
3.2、类中的方法声明和基本使用
方法:描述类应该具有的功能
| 无返回值 | 有返回值 | |
|---|---|---|
| 无形参 | void 方法名(){} | 返回值类型 void 方法名(){} |
| 有形参 | void 方法名(形参类型 形参){} | 返回值类型 void 方法名(){} |
举例:
public void eat(){}
public void sleep(int hour){}
public String getName(){}
public String getNation(String nation){}
方法的声明
权限修饰符 返回值类型 方法名(形参列表){
方法体
}
注意:static、final、abstract 来修饰的方法,后面再讲。
方法的命名规则
- 方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:
addPerson - 下划线可能出现在
JUnit测试方法名称中用以分隔名称的逻辑组件。一个典型的模式是:test<MethodUnderTest>_<state>,例如 testPop_emptyStack。
说明:
-
权限修饰符:默认方法的权限修饰符先都使用
public,Java规定的4种权限修饰符:private、public、缺省、protected -->封装性再细说 -
返回值类型
- 如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用
return关键字来返回指定类型的变量或常量:return 数据。 - 如果方法没有返回值,则方法声明时,使用
void来表示。通常,没有返回值的方法中,就不需要使用return。但是,如果使用的话,只能return;表示结束此方法的意思。
- 如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用
-
方法名:属于标识符,遵循标识符的规则和规范,见名知意
-
方法体:方法功能的体现。
方法调用:方法分为静态方法和非静态方法
- 非静态-实例方法可以通过
对象.方法调用 - 静态方法可以通过
类名.方法调用
方法的使用细节注意:
- 方法的使用中,可以调用当前类的属性或方法,其实省略了this。
- 特殊的:方法A中又调用了方法A,递归方法。
- 方法中,不可以定义方法。
class Customer{
//属性
String name;
int age;
boolean isMale;
//方法
public void sleep(int hour){
System.out.println("休息了" + hour + "个小时");
eat(); //方法中可以调用当前类的方法,其实省略了this
//sleep(10); //递归方法
}
public String getName(){
if(age > 18){ //方法中可以调用当前类的属性age,省略了this
return name;
}else{
return "Tom";
}
}
3.3、方法的重载(overload)
定义: 在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
- 同一个类、相同方法名
- 参数列表不同:参数个数不同,参数类型不同
举例: Arrays类中重载的binarySearch()方法
重载特点: 跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!只看方法名和方法参数列表的不同
package com.lanmeix.java1;
public class OverLoadTest {
public static void main(String[] args) {
OverLoadTest test = new OverLoadTest();
test.getSum(1,2);//会优先选择第一个getSum方法,精确匹配优先
}
//如下的4个方法构成了重载
public void getSum(int i,int j){
System.out.println("1");
}
public void getSum(double d1,double d2){
System.out.println("2");
}
public void getSum(String s ,int i){
System.out.println("3");
}
public void getSum(int i,String s){
System.out.println("4");
}
}
如下的3个方法不能与上述4个方法构成重载
public int getSum(int i,int j){
return 0;
}
public void getSum(int m,int n){}
private void getSum(int i,int j){}
3.4、新特性:可变个数的形参
可变个数形参的方法:是jdk5.0新增的内容
//JDK 5.0以前:采用数组形参来定义方法,传入多个同一类型变量
public static void test(int a, String[] books);
//JDK5.0:采用可变个数形参来定义方法,传入多个同一类型变量
public static void test(int a, String …books);
具体使用:
-
可变个数形参的格式:数据类型 ... 变量名
-
当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。
-
可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
-
可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
public void show(String ... strs){
System.out.println("show(String ... strs)");
for(int i = 0;i < strs.length;i++){
System.out.println(strs[i]);
}
}
//不能与上一个方法同时存在,不构成重载
public void show(String[] strs){}
- 可变个数形参在方法的形参中,必须声明在末尾,防止参数类型冲突
//The variable argument type String of the method
//show must be the last parameter
public void show(String ...strs,int i){}
- 可变个数形参在方法的形参中,最多只能声明一个可变形参
实例演示:
public class MethodArgsTest {
public static void main(String[] args) {
MethodArgsTest test = new MethodArgsTest();
test.show(12);
test.show("hello");
test.show("hello","world");
test.show();
test.show(new String[]{"AA","BB","CC"}); //这样是正确的,相当于jdk5.0以前的写法
}
public void show(int i){}
public void show(String s){
System.out.println("show(String)");
}
public void show(String ... strs){
System.out.println("show(String ... strs)");
for(int i = 0;i < strs.length;i++){
System.out.println(strs[i]);
}
}
}
3.5、方法参数的值传递机制
方法,必须由其所在类或对象调用才有意义。若方法含有参数:
- 形参:方法声明时的参数
- 实参: 方法调用时实际传给形参的参数值
Java的实参值如何传入方法呢?
- Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
- 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
- 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
引用传递--针对于方法内变量的赋值举例
- 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
- 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
public class ValueTransferTest {
public static void main(String[] args) {
System.out.println("***********基本数据类型:****************");
int m = 10;
int n = m;
System.out.println("m = " + m + ", n = " + n);
n = 20;
System.out.println("m = " + m + ", n = " + n);
System.out.println("***********引用数据类型:****************");
Order o1 = new Order();
o1.orderId = 1001;
Order o2 = o1; //赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体。
System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);
o2.orderId = 1002;
System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);
}
}
class Order{
int orderId;
}
参数传递机制:值传递-----针对于方法的参数概念
- 形参:方法定义时,声明的小括号内的参数
- 实参:方法调用时,实际传递给形参的数据
值传递机制实例:针对基本数据类型
/*
* 方法的形参的传递机制:值传递
*/
public class ValueTransferTest1 {
public static void main(String[] args) {
int m = 10;
int n = 20;
System.out.println("m = " + m + ", n = " + n);
ValueTransferTest1 test = new ValueTransferTest1();
test.swap(m, n);
System.out.println("m = " + m + ", n = " + n); //m=10,n=20,没有发生交换
}
public void swap(int m,int n){
int temp = m ;
m = n;
n = temp;
}
}
理解:swap方法执行完以后,里面的变量就销毁回收,所以然后main方法打印的还是原来的值,可以延伸在数组元素的交换
值传递机制实例:针对引用数据类型
public class ValueTransferTest2 {
public static void main(String[] args) {
Data data = new Data();
data.m = 10;
data.n = 20;
System.out.println("m = " + data.m + ", n = " + data.n);
ValueTransferTest2 test = new ValueTransferTest2();
test.swap(data); //传入引用数据类型地址值
System.out.println("m = " + data.m + ", n = " + data.n);//发生了交换
}
public void swap(Data data){
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m;
int n;
}
3.6、递归方法的使用
递归方法:一个方法体内调用它自身。 如何理解递归方法?
- 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
- 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
例1:计算1-100之间所有自然数的和
public class RecursionTest {
public static void main(String[] args) {
// 方式一:
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println(sum);
// 方式二:递归
RecursionTest test = new RecursionTest();
int sum1 = test.getSum(100);
System.out.println(sum1);
}
//计算1-n之间所有自然数的和
public int getSum(int n) {
if (n == 1) {
return 1;
}else {
return n + getSum(n - 1);
}
}
}
例2:计算1-n之间所有自然数的乘积:n!
// 例2:计算1-n之间所有自然数的乘积:n!
public int getSum1(int n) {
if (n == 1) {
return 1;
} else {
return n * getSum1(n - 1);
}
}
例3:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),其中n是大于0的整数,求f(10)的值。
public class RecursionTest {
public static void main(String[] args) {
int value = test.f(10);
System.out.println(value);
}
//例3:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
//其中n是大于0的整数,求f(10)的值。
public int f(int n){
if(n == 0){
return 1;
}else if(n == 1){
return 4;
}else{
//return f(n + 2) - 2 * f(n + 1);//会内存溢出
return 2*f(n - 1) + f(n - 2);
}
}
}
其他:
- 斐波那契数列
- 汉诺塔问题
- 快排
3.7、return关键字
使用范围:使用在方法体中
作用:
- 结束方法
- 针对于有返回值类型的方法,使用"return 数据"方法返回所要的数据。
注意点:return关键字后面不可以声明执行语句。
public void eat(){
System.out.println("客户吃饭");
return;
//return后不可以声明表达式
//System.out.println("hello");
}
4、构造器Constructor
构造器的作用:
- 创建对象
- 初始化对象属性的信息
- 初始化其他一些自定义信息
使用说明:
- 如果没显式的定义类的构造器的话,则系统默认提供一个空参的构造器
- 定义构造器的格式:
权限修饰符 类名(形参列表){} - 一个类中定义的多个构造器,彼此构成重载
- 一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器,但是我们可以显示的将空参构造器写出来
- 一个类中,至少会有一个构造器(空参)。
举例:
public class Person {
// 属性
private String name;
private int age;
private String sex;
// 空参构造器
public Person() {
}
// 全参构造器
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
5、万事万物皆对象
在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构。涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象。例如,表就是一个对象、文件File、网络资源URL
内存解析的说明
- 引用类型的变量,只可能存储两类值:
null或 地址值(含变量的类型) - 自定义类是引用数据类型,所以student数组里面存放的是学生对象的地址值或
null。
JVM内存解析简述
编译完 java 源程序以后,生成一个或多个字节码文件(.class)。然后,JVM中类的加载器和解释器会对生成的字节码文件进行解释运行。意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析。
《JVM规范》
- 虚拟机栈:即为平时提到的栈结构。我们将局部变量存储在栈结构中。通常所说的 栈 Stack 就是指虚拟机栈 。 虚拟机栈用于存储局部变量等 。局部变量表存放了编译期可知长度的各种基本数据类型,如:boolean、byte、char、short、int、float、long、double、对象引用(reference类型它不等同于对象本身,是对象在堆内存的首地址<对象名字和地址>) 。方法执行完自动释放变量。(方法里面的变量都叫局部变量)
- 堆:我们将new出来的结构(比如:数组、对象)加载在堆空间中。此外,对象的属性(非static的)也是加载在堆空间中。此内存区域的唯一目的就是:存放对象实例,几乎所有的对象实例 (
new出来的结构,属性)都在这里分配内存。这一点在Java 虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。 - 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
5.1、对象的内存解析简述
【案例】
5.2、String类型的内存解析
字符串类型不同于其他引用数据类型,需要特殊说明,
public class ValueTransferTest {
public static void main(String[] args) {
String s1 = "hello";
ValueTransferTest test = new ValueTransferTest();
test.change(s1);
//值传递,方法里面的形参s只不过是一个拷贝的副本,可以看做是s2,只是两者都指向hello罢了
System.out.println(s1);//hello
}
public void change(String s){
s = "hi~~"; //只能新造一个,所以s指向的是另外一个hello,然后将hello改成hi,并且指向hi
}
}
之所以 System.out.println(s1);//hello 是这样的。是因为string类型字符串会保存在方法区的常量池,方法区不可更改,更改只能新造一个,所以当change方法执行完毕,hi回收,常量池就只剩下s1指向的hello了。
6、匿名对象
我们创建的对象,没有显式的赋给一个变量名。即为匿名对象
- 特征:匿名对象只能调用一次。
public class InstanceTest {
public static void main(String[] args) {
//匿名对象
new Phone().price = 1999;
new Phone().showPrice();//0.0
//***匿名对象的传参**********************
PhoneMall mall = new PhoneMall();
mall.show(new Phone());
}
}
class PhoneMall{
public void show(Phone phone){
phone.sendEmail();
phone.playGame();
}
}
class Phone{
double price;//价格
public void sendEmail(){
System.out.println("发送邮件");
}
public void playGame(){
System.out.println("玩游戏");
}
public void showPrice(){
System.out.println("手机价格为:" + price);
}
}
7、面向对象的特征一:封装与隐藏
为什么要引入封装性?
- 我们程序设计追求 “高内聚,低耦合” 。
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅对外暴露少量的方法用于使用。
- 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
问题引入
- 当我们创建一个类的对象以后,我们可以通过
"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。除此之外,没其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:对某个属性进行setter操作的同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private),此时,针对于属性就体现了封装性。
封装性思想具体的代码体现:
- 体现1:将类的属性私有化(private),这样只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。 同时,提供公共的
public方法来获取(getXxx)和设置(setXxx)此私有属性的值,当构造器出现后,可以进行属性的初始化,并不意味着set方法没用了,因为属性私有化,set方法可以起到在外面在通过对象设置属性值的作用。通过set和get方法,属性被封装起来,类的外部无法直接访问和修改属性值,只有通过方法进行。
//属性私有化,就不能通过在外部通过 对象.属性 方式进行属性的获取和修改
private double radius;
//生成公共的set/get方法,可以在外部通过 对象.方法 方式进行属性的获取和修改
public void setRadius(double radius){
this.radius = radius;
}
public double getRadius(){
return radius;
}
- 体现2:增加灵活性。在set方法中,你可以添加额外的验证逻辑,确保属性值的合法性。
get和set方法为后期的维护和扩展提供了灵活性。如果直接访问字段,代码就不容易维护。通过方法,你可以随时改变方法内部的实现,而不影响使用它们的代码。
public void setAge(int age) {
if (age > 0) {
this.age = age;
} else {
System.out.println("年龄不能小于0!");
}
}
- 体现3:不对外暴露的私有的方法
- 体现4:单例模式(将构造器私有化)
- 体现5:如果不希望类在当前所在的包外被调用,可以将类设置为缺省的。
封装性的体现,需要权限修饰符来配合,Java规定的四种权限修饰符
- 权限范围从小到大顺序为:
private< 缺省 <protected<public - Java权限修饰符置于类的成员定义前,用来限定对象对该类成员的访问权限。4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类
- 对于class的权限修饰只可以用 public和 default
public类可以在任意地方被访问。default类只可以被同一个包内部的类访问。
- 具体的修饰范围:
8、属性赋值情况说明
总结:前面提到了很多变量赋值情况,通过set方法,构造器等,因此有一个属性赋值的先后顺序
- ① 默认初始化值
- ② 显式初始化
- ③ 构造器中初始化
- ④ 通过
"对象.方法"或"对象.属性"的方式,赋值 - 以上操作的先后顺序:① - ② - ③ - ④
package com.lanmeix.java1;
public class UserTest {
public static void main(String[] args) {
User u = new User();
System.out.println(u.age);
User u1 = new User(2);
u1.setAge(3);
u1.setAge(5);
System.out.println(u1.age);
}
}
class User{
String name; //默认初始化值null
int age = 1; //显示初始化age=1
public User(){
}
public User(int a){ //构造器中初始化
age = a;
}
public void setAge(int a){ //set方法为属性赋值
age = a;
}
}
9、基本关键字
9.1、this
定义
- 在 Java 中,
this关键字比较难理解,它的作用和其词义很接近。 - 它在方法内部使用,即这个方法所属对象的引用;
- 它在构造器内部使用,表示该构造器正在初始化的对象。
this可以调用的结构:属性、方法;构造器
什么时候使用this关键字呢?
- 当在方法内需要用到调用该方法的对象时,就用
this - 具体的:当方法或构造器形参和属性名相同时,我们可以用
this来区分属性和局部变量
class Person{
private String name;
private int age;
public Person(String name){
this.name = name;//区分属性和局部变量,this可以省略
}
public void setName(String name){
this.name = name; //区分属性和局部变量,this可以省略
}
public String getName(){
return this.name;
}
}
this 调用方法:
this理解为:当前对象 或 当前正在创建的对象- 在类的方法或构造器中,我们可以使用
this.属性或this.方法的方式,调用当前对象属性或方法。但是,通常情况下,我们都择省略this。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用this.变量的方式,表明此变量是属性,而非形参。 - 使用
this访问属性和方法时,如果在本类中未找到,会从父类中查找
class Person{
private String name;
private int age;
public Person(){
this.eat(); //this调用方法eat
String info = "Person初始化时,需要考虑如下的1,2,3,4...(共40行代码)";
System.out.println(info);
}
public void eat(){
System.out.println("人吃饭");
System.out.println("Person 类 ----> " + this .name) ;
this.study(); //this调用方法study,当前调用 study 方法的this是当前 Person对象
}
public void study(){
System.out.println("人学习");
}
}
this调用构造器:
- 我们在类的构造器中,可以显式的使用
this(形参列表)方式,调用本类中指定的其他构造器 - 构造器中不能通过
this(形参列表)方式调用自己 - 如果一个类中有n个构造器,则最多有 n-1 构造器中使用了
this(形参列表) - 规定:
this(形参列表)必须声明在当前构造器的首行 - 构造器内部,最多只能声明一个
this(形参列表),用来调用其他的构造器
class Person{
private String name;
private int age;
public Person(){ // 无参构造器
System.out.println("新对象实例化 ")
}
public Person(String name){
this(); // 调用本类中的无参构造器
this.name = name ;
}
public Person(String name,int age){
this(name) ; //调用有一个参数的构造器
this.age=age
}
public String getInfo(){
return "姓名: :" + name + ",年龄 :" + age
}
}
9.2、package
使用说明:
- 为了更好的实现项目中类的管理,提供包的概念
- 使用
package声明类或接口所属的包,声明在源文件的首行 - 包,属于标识符,遵循标识符的命名规则、规范(
xxxyyyzzz)、“见名知意” - 每
.一次,就代表一层文件目录。
包的作用:
- 包帮助管理大型软件系统将功能相近的类或接口划分到同一个包中 。 比如 MVC 的设计模式
- 包可以包含类和 子包 划分项目层次,便于管理
- 解决类命名冲突的问题:如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
- 控制访问权限:包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。
包语句的语法格式为:
package pkg1[.pkg2[.pkg3…]];
9.3、import
为使用定义在不同包中的 Java 类,需用 import 语句来引入指定包层次下所需要的类或全部类 。 import 语句告诉编译器到哪里去寻找类。
语法格式:
import 包名.类名 //import:导入
如果在一个包中,一个类想要使用本包中的另一个类,那么该包名可以省略。
注意:
- 在源文件中显式的使用
import结构导入指定包下的类、接口 - 声明在包的声明和类的声明之间
- 如果需要导入多个结构,则并列写出即可
- 可以使用
xxx.*的方式,表示可以导入xxx包下的所结构 - 如果使用的类或接口是
java.lang包下定义的,则可以省略import结构 - 如果使用的类或接口是本包下定义的,则可以省略
import结构 - 如果在源文件中,使用了不同包下的同名的类,则必须至少一个类需要以全类名的方式显示。
- 使用
xxx.*方式表明可以调用xxx包下的所结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入 import static:导入指定类或接口中的静态结构:属性或方法。
10、JavaBean
JavaBean 是一种 Java 语言写成的可重用组件。所谓JavaBean,是指符合如下标准的 Java 类:
- 类是公共的
- 一个无参的公共的构造器
- 属性,且对应的
get、set方法
public class JavaBean {
private String name; //属性一般定义为private
private int age;
public JavaBean() {
}
public int getAge() {
return age;
}
public void setAge(int a) {
age = a;
}
public String getName() {
return name ;
}
public void setName(String n) {
name = n;
}
}
如果没有显示的声明构造器,则默认构造器和类的权限一样
用户可以使用 JavaBean 将功能、处理、值、数据库访问和其他任何可以用 Java 代码创造的对象进行打包,并且其他的开发者可以通过内部的 JSP页面、Servlet 、其他 JavaBean、applet 程序或者应用来使用这些对象。用户可以认为 JavaBean 提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
11、UML类图
+表示 public 类型,-表示 private 类型,#表示protected类型- 方法的写法:
方法的类型(+、-) 方法名(参数名: 参数类型):返回值类型