面向对象 - 上
前言
学习面向对象的三大方向
一、类与对象
结构:属性、方法、构造器(必须要懂)
代码块、内部类(要知道怎么用)
二、面向对象的三大特性
封装性、继承性、多态性
三、其它关键字的使用
this、super、static、final、abstract等…
类与对象
介绍
面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做
例子: 人把大象装进冰箱
① 打开冰箱门
② 把大象装进去
③ 关上冰箱门
每一个行为步骤都是面向过程
面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做
例子: 人把大象装进冰箱
① 人{
冰箱.打开();
大象.进入();
冰箱.关闭();
}
② 冰箱{
打开();
关闭();
}
③ 大象{
进入();
}
把每一个步骤细分,精确到谁来做,做什么,怎么做等…
Java 语言的基本元素:类与对象(万事万物皆对象)
1、类是对一类事物的描述,是抽象的、概念上的定义
2、对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
面向对象程序设计的重点是类的设计
设计类,就是设计类的成员
简单说明:类是对象的抽象,对象是类的实例
一、设计类,其实就是设计类的成员
属性 = 成员变量 = field = 域/字段(其它语言中的叫法)
方法 = 成员方法 = method = 函数(其它语言中的叫法)
1、属性:对应类中的成员变量
2、行为:对应类中的成员方法
二、类和对象的使用(面向对象思想落地的实现)
1、创建类,设计类的成员
2、创建类的实例
3、通过 “对象.属性” 或 “对象.方法” 调用对象的结构
三、如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性(非 static(静态)的(也就是没有加上static关键字的))
意味着:如果我们修改了一个对象的属性 A,则不会影响另一个对象的属性 A
例子:
public class Test_02 {
public static void main(String[] args) {
User user = new User();
user.name = "张三";
// 返回 张三
System.out.println(user.name);
User user1 = new User();
// 返回 null,因为这是一个新的对象中的数据
System.out.println(user1.name);
}
}
class User {
String name;
int age;
}
四、对象的内存解析
如果没有给对象中的属性进行赋值的话,那么拿到的就是对应类型的默认初始值,比如 0、0.0、null等
类中属性的使用
属性(成员变量) 与 局部变量
相同点:
1、定义变量的格式一致:数据类型 变量名 = 变量值
2、先声明,后使用
3、变量都有对应的作用域
不同点:
1、在类中声明的位置不同
属性:直接定义在类的 { }(大括号)中
局部变量:声明在方法内、方法形参、代码块内、构造器形参、构成器内部的变量
2、权限修饰符不同
属性:可以在声明变量(属性)时,指明其权限,使用权限修饰符
局部变量:不可以使用权限修饰符
常用的权限修饰符:public、private、protected、default(默认修饰符)
3、默认初始值的不同
属性:根据对应的类型,有默认初始值
整型(short、byte、int、long):0
浮点型(double、float):0.0
char:‘0’
boolean: false
引用数据类型(类、数组、接口):null
局部变量:没有默认初始值
注意:在调用方法的时候我们可以给形参动态赋值,但是在方法内部定义的变量无法赋值
4、在内存中加载的位置不同
属性:加载到堆空间中(静态变量放在方法区中)
局部变量:加载到栈空间
这里说的属性就是 成员变量
类中方法的声明和使用
方法:描述类应该具有的功能
比如:Math类(随机数等…)、Scanner类(控制台输入)、Arrays类(排序、查找等)
方法(void 表示没有返回值,如果是一个类型那么就需要返回一个对应类型的值)
语法
访问修饰符 返回类型 方法名( ) { 方法体 }
访问修饰符 返回类型 方法名(形参列表) { 方法体 }
方法的使用
1、方法的使用中,可以调用当前类中的属性与方法
方法中是可以调方法的,并且可以调用自己;
比如在 A方法中调用A方法,这种操作叫做 “递归调用”;但是这种操作是不能随意使用的,在错误的调用时可能会造成栈内存溢出!
2、方法中可以调用其它方法,但是不能定义其它方法!
return 关键字的使用
1、使用范围:使用在方法体中
2、作用:
- 结束一个方法
- 针对于有返回值的方法,使用 “return 数据” 方法返回所需要的的数据
注意:return 下面不能再编写其它执行语句了!
说明
1、权限修饰符:public、protected、default(默认修饰符)、private
2、返回值说明:有返回值 与 没有返回值
-
如果方法有返回值,那么必须在方法声明时,指定返回值的类型;同时方法中需要使用 return 关键字来返回指定类型的值
-
如果方法没有返回值,那么需要使用 void 进行标识(没有返回值的时候不需要使用 return,如果需要使用,那么就直接写 return 即可,后面不需要加上对应的返回值)
-
定义方法的时候该不该有返回值?
根据对应的需求进行编写即可!比如说查询出数组中的所有元素,并显示出来给用户进行查看,那么这个时候就需要使用返回值…
3、方法名:属于标识符,遵循标识符的规则和规范,名字需要 “见名知意”
4、形参:可以声明 0 个、1个 或多个
-
格式:数据类型1 形参1,数据类型2 形参2,数据类型n 形参n…(用逗号隔开)
-
定义方法时要不要形参?
根据对应的需求进行编写!
5、方法体:方法功能的体现
方法的重载
概念
- 在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
- 两同一不同:同一个类;同一个方法名;不同的参数个数与类型
- 参数列表的个数和类型不同
- 简单来说就是同名不同参
特点
- 与方法的权限修饰符、返回值类型形参变量名、方法体无关,只看参数列表,且参数列表必须不同(参数个数或参数类型);
- 调用时,根据方法参数列表的不同来区别!
案例
/**
* 在通过对象调用方法时,如何确定某一个指定的方法:
* 方法名 -> 参数列表
*/
public class Test_09 {
public static void main(String[] args) {
Test_09 test = new Test_09();
test.getSum(1, 2);
test.getSum(18, "小明");
}
// 如下的三个方法就构成了重载
public void getSum(int i, int j) {
System.out.println(i + j);
}
public void getSum(int age, String name) {
System.out.println("我叫:" + name + ";今年" + age + "岁了");
}
public int getSum(char i, boolean j) {
return 0;
}
// 错误重构
// public void getSum(int i,int j){}
// public int getSum(int q,int w){return 0;}
// private void getSum(int r,int p){}
}
Varargs(variable number of arguments)机制
了解
JDK 5.0以前:采用数组形参来定义方法,传入多个同一类型变量
public static void test(int a ,String[] books);
JDK 5.0:采用可变个数形参来定义方法,传入多个同一类型变量
public static void test(int a ,String… books);
具体使用
- 可变个数形参的格式:数据类型… 变量名
- 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个等…
- 可变个数的形参方法与本类中的方法名相同,形参不同的方法之间构成重载
- 可变个数的形参方法与本类中的方法名相同,形参类型也相同的数组之间不构成重载(二者不能共存)
- 可变个数形参在方法的形参中,只能声明在末尾(因为一旦声明在前面,编译器就会搞不清楚你传入的参数是给第一个形参还是第二个形参)
- 可变个数形参在方法的形参中,最多只能声明一个
public class Test_11 {
public static void main(String[] args) {
Test_11 test = new Test_11();
test.show("Hello");
test.show("J", "D", "K");
test.show(new int[]{1, 2, 4, 5});
}
public void show(String i) {
System.out.println("show(String i)");
}
public void show(int[] j) {
System.out.println("show(int[] j)");
}
/*
注意:
String... str 和 String[] str 在重构时只能存在一个
比如在这里已经定义了 public void show(String... str)
那么就不能再定义 public void show(String[] str)
*/
public void show(String... str) {
System.out.println("show(String... str)");
}
}
方法参数的值传递机制
变量的赋值
- 如果是基本数据类型,那么赋值的是变量所保存的数据值
- 如果是引用数据类型,那么赋值的是变量所保存的数据的地址值
基本数据类型案例
public class Test_12 {
public static void main(String[] args) {
int i = 10;
int j = i;
System.out.println(i + "---" + j); // 返回10---10
j = 12;
System.out.println(i + "---" + j); // 返回10---12
Test test = new Test();
test.name = "小明";
Test test1 = test;
System.out.println(test.name + "---" + test1.name); // 返回小明---小明
test1.name = "小白";
System.out.println(test.name + "---" + test1.name); // 返回小白---小白
}
}
class Test {
String name;
int age;
}
引用数据类型案例
public class Test_14 {
public static void main(String[] args) {
Data data = new Data();
data.m = 10;
data.n = 20;
System.out.println(data.m + "---" + data.n); // 返回10---20
Test_14 test = new Test_14();
test.swap(data);
/*
返回20---10
因为引用数据类型指定的是对应地址值中的数据,而这里的对象地址指向的是同一个,所以可以交换成功
*/
System.out.println(data.m + "---" + data.n);
}
/**
* 交换 m 和 n 的值
*/
public void swap(Data data){
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m;
int n;
}
方法形参的传递机制
形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据
值传递机制:
- 如果参数是基本数据类型,此时实参赋给形参真实存储的数据源
- 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值
import java.util.Arrays;
public class Test_13 {
public static void main(String[] args) {
int i = 10;
int j = 20;
System.out.println(i + "---" + j);
// 交换两个参数
Test_13 test = new Test_13();
test.exchange(i, j);
/*
返回10---20
因为此时打印的 i 和 j 都还是 mian 方法中的值,并不是 exchange 方法中交换后的数据
*/
System.out.println(i + "---" + j);
int[] arr = new int[]{2, 4, 6, 3, 1, 9};
test.bubbleSort(arr);
}
// 交换两个参数
public void exchange(int i, int j) {
int temp = i;
i = j;
j = temp;
// 打印 20---10,因为此时的i和j已经完成了交换,打印的是exchange方法中已经交换完了的值
//System.out.println(i + "---" + j);
}
public void exchange2(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//冒泡排序
public void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
//int temp = arr[j];
//arr[j] = arr[j + 1];
//arr[j + 1] = temp;
/*
错误演示:
把上面的替换方式修改为刚才的替换方法,执行后可以看到结果并没有正确的执行
因为每一次调用的都是exchange方法中的实参,并不是当前方法的参数,所以最后的结果不会受到任何影响
*/
//exchange(arr[j], arr[j + 1]);
/*
正确演示:
将当前需要排序的数组传入到对应的替换方法中进行替换,此时指定的就是同一个地址值内的数据
*/
exchange2(arr, j, j + 1);
}
}
}
System.out.println(Arrays.toString(arr));
}
}
构造器(构造方法)的使用
作用
-
创建对象
-
初始化对象的属性
说明
-
如果没有显式的定义类的构造器的话,那么系统就会默认提供一个空参的构造器
-
定义构造器的格式:权限修饰符 类名(形参列表){}
-
一个类中可以定义多个构造器,彼此构成重载
-
一旦我们手动在类中定义了构造器(不管有参无参),那么系统就不会在提供默认的空参构造器了
-
一个类中至少会有一个构造器
-
构造器的默认权限(修饰符)和类的权限是一致的
注意:构造方法跟方法不是一个概念,构造方法是一个独立的结构!
public class Test_21 {
public static void main(String[] args) {
// 创建类的对象
Persons persons = new Persons();
persons.eat();
}
}
class Persons {
// 属性
String name;
String age;
// 构造器
public Persons() {
System.out.println("Persons()...");
}
public Persons(String name) {
this.name = name;
}
public Persons(String name, String age) {
this.name = name;
this.age = age;
}
// 方法
public void eat() {
System.out.println("吃饭");
}
public void study() {
System.out.println("学习");
}
}
练习
简单练习
-
编写程序,声明一个 method 方法,在方法中打印一个10*8 的 * 型矩形, 在 main 方法中调用该方法。
-
修改上一个程序,在 method 方法中,除打印一个 10*8 的 * 型矩形外,再计算该矩形的面积,并将其作为方法返回值。在 main 方法中调用该方法,接收返回的面积值并打印。
-
修改上一个程序,在 method 方法提供 m 和 n 两个参数,方法中打印一个 m*n 的 * 型矩形,并计算该矩形的面积, 将其作为方法返回值。在 main 方法中调用该方法,接收返回的面积值并打印。
public class Test_06 {
public static void main(String[] args) {
ThreeExercises threeExercises = new ThreeExercises();
// 打印矩形
threeExercises.method();
// 计算面积
System.out.println("面积为:" + threeExercises.rectangularArea());
// 打印一个动态矩形,并计算面积
System.out.println("面积为:" + threeExercises.calculateTheArea(3, 6));
}
}
class ThreeExercises {
/**
* 一、打印 10*8 的矩形
* 如果功能给出一个具体的效果,那么就可以不加入形参
*/
public void method() {
// 行
for (int i = 0; i < 10; i++) {
// 列
for (int j = 0; j < 8; j++) {
System.out.print("*");
}
System.out.println();
}
}
/**
* 二、计算矩形的面积
*/
public double rectangularArea() {
method();
return 10 * 8;
}
/**
* 三、打印一个动态矩形,并计算面积
*/
public double calculateTheArea(double m, double n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
System.out.print("*");
}
System.out.println();
}
return m * n;
}
}
数组对象练习
定义类 Student,包含三个属性:学号 number(int),年级 state(int),成绩 score(int);创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:
-
生成随机数:Math.random(),返回值类型 double;
-
四舍五入取整:Math.round(double d),返回值类型 long。
public class Test_07 {
public static void main(String[] args) {
// 声明一个对象数组用于存储学生信息
Student[] student = new Student[20];
Student user = new Student();
user.createAStudent(student);
/*
一、打印三年级的学生信息
*/
Student stu = new Student();
stu.findBasedOnGrade(student);
/*
二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
*/
Student stus = new Student();
stus.bubbleSort(student);
}
}
class Student {
/**
* 学号 number
* 年级 state
* 成绩 score
*/
int number;
int state;
int score;
/**
* 创建学生
*/
public void createAStudent(Student[] student) {
// 根据需求设置用户信息
for (int i = 0; i < student.length; i++) {
// 一个对象只能存储一个学生的信息,所以在循环中还要创建我们所需要的多个对象(不然就会出现空指针异常)
student[i] = new Student();
student[i].number = (i + 1);
student[i].state = (int) (Math.random() * 3 + 1);
student[i].score = (int) (Math.random() * 100 + 1);
}
}
/**
* 一、打印三年级的学生信息
*/
public void findBasedOnGrade(Student[] student) {
for (Student s : student) {
if (s.state == 3) {
System.out.println("学号:" + s.number + ";年级:" + s.state + ";成绩:" + s.score);
}
}
}
/**
* 二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
*/
public void bubbleSort(Student[] student) {
for (int i = 0; i < student.length - 1; i++) {
for (int j = 0; j < student.length - 1 - i; j++) {
if (student[j].score < student[j + 1].score) {
int temp = student[j].score;
student[j].score = student[j + 1].score;
student[j + 1].score = temp;
}
}
}
for (Student s : student) {
System.out.println("学号:" + s.number + ";年级:" + s.state + ";成绩:" + s.score);
}
}
}
方法重载练习
一、编写程序,定义三个重载方法并调用。方法名为 mOL。
- 三个方法分别接收一个 int 参数、两个 int 参数、一个字符串参数。
- 分别执行平方运算并输出结果,相乘并输出结果,输出字符串信息。
- 在主类的 main ()方法中分别用参数区别调用三个方法。
二、定义三个重载方法 max()
- 第一个方法求两个 int 值中的最大值;
- 第二个方法求两个 double 值中的最大值;
- 第三个方法求三个 double 值中的最大值;
- 分别调用三个方法。
public class Test_10 {
public static void main(String[] args) {
Test_10 test = new Test_10();
test.mOL(10);
test.mOL(2, 4);
test.mOL("小猫咪");
System.out.println(test.max(24, 31));
System.out.println(test.max(10.0, 7.0));
System.out.println(test.max(12, 5, 6));
}
public void mOL(int sum) {
System.out.println(sum * sum);
}
public void mOL(int i, int j) {
System.out.println(i * j);
}
public void mOL(String val) {
System.out.println(val);
}
public int max(int i, int j) {
if (i < j) {
return i;
}
return j;
}
public double max(double a, double b) {
return a > b ? a : b;
}
public double max(double i, double j, double k) {
double max = (i > j) ? i : j;
return (max > k) ? max : k;
}
}
将对象作为参数传递给方法
-
定义一个 Circle 类,包含一个 double 型的 radius 属性代表圆的半径,一个 findArea() 方法返回圆的面积。
-
定义一个类 PassObject,在类中定义一个方法 printAreas(),该方法的定义如下:
public void printAreas(Circle c, int time)
在 printAreas 方法中打印输出1到time之间的每个整数半径值,以及对应的面积。
例如:times 为 5,则输出半径 1,2,3,4,5,以及对应的圆面积。
-
在 main 方法中调用 printAreas() 方法,调用完毕后输出当前半径值。
程序运行结果如图所示:
public class Test_16 {
public static void main(String[] args) {
PassObject passObject = new PassObject();
// 在只使用一次对象的时候就可以使用匿名对象方式进行编写
passObject.printAreas(new Circles(), 5);
}
}
class Circles {
double radius;
public double findArea() {
return Math.PI * radius * radius;
}
}
class PassObject {
public void printAreas(Circles c, int time) {
for (int i = 0; i < time; i++) {
c.radius = (i + 1);
System.out.println((i + 1) + "\t" + c.findArea());
}
System.out.println("new radius is " + (time + 1));
}
}
递归方法
说明
- 一个方法体内调用它本身
- 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
- 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
public class Test_17 {
public static void main(String[] args) {
Test_17 test = new Test_17();
System.out.println("案例一:" + test.getSum(100));
System.out.println("案例二:" + test.f(10));
System.out.println("案例三:" + test.Fibonacci(9));
}
/**
* 案例一
* 计算1-100之间所有自然数的和
*/
public int getSum(int num) {
if (num == 1) {
return 1;
} else {
return num + getSum(num - 1);
}
}
/**
* 案例二
* 已知有一个数列: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 {
// 报错:Exception in thread "main" java.lang.StackOverflowError(栈溢出)
//return f(n + 2) - 2 * f(n + 1);
return 2 * f(n - 1) + f(n - 2);
}
}
/**
* 案例三:斐波那契数列
* 输入一个数据n,计算斐波那契数列(Fibonacci)的第n个值
* 1 1 2 3 5 8 13 21 34 55
* 规律:一个数等于前两个数之和
* 要求:计算斐波那契数列(Fibonacci)的第n个值,并将整个数列打印出来
*/
public int Fibonacci(int n) {
return n < 2 ? 1 : (Fibonacci(n - 1) + Fibonacci(n - 2));
}
/**
* 案例四:汉诺塔问题
* 案例五:快速排序
* 自行百度...
*/
}
使用构造方法计算三角形的面积
编写两个类,TriAngle 和 TriAngleTest,其中 TriAngle 类中声明私有的底边长 base 和高 height,同时声明公共方法访问私有变量。
此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
public class TriAngleTest {
public static void main(String[] args) {
TriAngle triAngle = new TriAngle(2, 4.3);
System.out.println("三角形面积为:" + triAngle.getBase() * triAngle.getHeight());
}
}
class TriAngle {
/**
* 底边长:base
* 高:height
*/
private double base;
private double height;
public TriAngle() {
}
public TriAngle(double base, double height) {
this.base = base;
this.height = height;
}
public double getBase() {
return base;
}
public void setBase(double base) {
this.base = base;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
}
构造器练习
-
定义Student类,有4个属性:
String name; int age; String school; String major;
-
定义Student类的3个构造器:
第一个构造器Student(String n, int a)设置类的name和age属性;
第二个构造器Student(String n, int a, String s)设置类的name, age 和school属性;
第三个构造器Student(String n, int a, String s, String m)设置类的name, age ,school和major属性;
-
在main方法中分别调用不同的构造器创建的对象,并输出其属性值。
public class Test_24 {
public static void main(String[] args) {
Student students1 = new Student("小明", 18);
System.out.println(students1.getName() + "---" + students1.getAge());
Student students2 = new Student("小美", 12, "清华");
System.out.println(students2.getName() + "---" + students2.getAge() + "---" + students2.getSchool());
Student students3 = new Student("小苍", 26, "北大", "heiheihei");
System.out.println(students3.getName() + "---" + students3.getAge() + "---" + students3.getSchool() + "---" + students3.getMajor());
}
}
class Student {
private String name;
private int age;
private String school;
private String major;
public Students() {
}
public Students(String name, int age) {
this.name = name;
this.age = age;
}
public Students(String name, int age, String school) {
this.name = name;
this.age = age;
this.school = school;
}
public Students(String name, int age, String school, String major) {
this.name = name;
this.age = age;
this.school = school;
this.major = major;
}
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 String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
}
理解
一、面向对象与面向过程(理解)
面向对象:强调的是功能行为,以函数为最小单位,考虑怎么做
面向过程:强调具备了功能的对象,以类 / 对象为最小单位,考虑谁来做
二、完成一个项目(或功能)的思路
面向对象分析方法分析问题的思路和步骤:
- 根据问题需要,选择问题所针对的现实世界中的实体。
- 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
- 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
- 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
三、面向对象中两个重要的概念
类与对象
关系:类是对象的抽象,对象是类的实例
四、面向对象思路落地实现的规则
- 创建类,设计类的成员
- 创建类的对象
- 通过 “对象.属性” 或 “对象.方法” 调用对象的结构
五、对象的创建与对象的内存解析
案例代码:
User user = new User();
User user2 = new User();
User user3 = user;
user3.age = 18;
说明
如果创建一个类的多个对象,那么每个对象都独立拥有一套类的属性(这就意味着如果我们修改一个对象的属性 a,则不会影响到另一个对象的属性 a)
内存解析
六、理解 “万事万物接对象”
- 在 java 语言中,我们将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构
- 涉及到 java 语言与前端 html、后端的数据库交互时,前后端的结构在 java 层面交互时,都体现为类、对象
七、匿名对象的使用
理解:我们创建的对象,没有显式的赋给一个变量名,即为匿名对象
特征:匿名对象只能调用一次
public class Test_08 {
public static void main(String[] args) {
Phone phone = new Phone();
phone.sendEmail();
phone.playGame();
// 匿名对象的使用
new Phone().sendEmail();
new Phone().playGame();
new Phone().price = 10;
new Phone().showPrice(); // 返回0.0,因为每一次创建的都是新的对象
/*
项目中一般在以下情况中会使用到匿名对象
*/
Phone phone1 = new Phone();
phone1.show(phone); // 以前使用的方式,把指定的对象传进去作为参数
phone1.show(new Phone()); // 使用匿名对象,创建一个新的对象作为参数
}
}
class Phone {
/**
* 价格
*/
double price;
public void sendEmail() {
System.out.println("发送邮件");
}
public void playGame() {
System.out.println("玩游戏");
}
public void showPrice() {
System.out.println("价格为:" + price);
}
public void show(Phone phone){
sendEmail();
playGame();
showPrice();
}
}
八、自定义工具类的好处
- 代码看起来更加简洁
- 增强代码复用性(防止代码冗余)
小问题
一、什么是方法的重载?
“两同一不同” :同一个类、相同的方法名;参数列表不同
如何调用确定的方法:方法名 -> 参数列表
二、说明 java 方法中的参数传递机制的具体表现
参数是基本数据类型时,传递的是值本身;
参数是引用数据类型时,传递的是地址值;
三、成员变量和局部变量在声明的位置、默认值、权限修饰符、内存分配的位置上有何不同?
声明位置:成员变量声明在类中,局部变量声明在方法中
默认值:成员变量有对应类型的默认值,局部变量没有默认值
权限修饰符:成员变量可以使用权限修饰符进行修饰,局部变量不能使用
内存分配:成员变量(new 出来的变量)放在堆中,局部变量放在栈中
了解
一、char 类型的数组直接打印会返回数组中的值,而其它类型的数据会返回地址值
public class Test_15 {
public static void main(String[] args) {
int[] arr = new int[]{1, 2, 3};
System.out.println(arr); // 地址值
char[] arrs = new char[]{'a', 'b', 'c'};
/*
返回abc
因为java给cahr数组类型单独配置了一个API
*/
System.out.println(arrs);
String[] str = new String[]{"aa", "bb", "cc"};
System.out.println(str); // 地址值
}
}
扩展
属性赋值过程
赋值的位置:
-
默认初始化值
-
显式初始化值(手动赋值)
-
构造器中初始化
-
通过 “对象.属性“ 或 “对象.方法” 的方式赋值
以上赋值的先后顺序:① - ② - ③ - ④
JavaBean
JavaBean是一种Java语言写成的可重用组件。
所谓 JavaBean,是指符合如下标准的Java类:
-
类是公共的
-
有一个无参的公共的构造器
-
有属性,且有对应的get、set方法
用户可以使用 JavaBean 将功能、处理、值、数据库访问和其他任何可以用 Java 代码创造的对象进行打包,并且其他的开发者可以通过内部的 JSP 页面、Servlet、其他 JavaBean、applet 程序或者应用来使用这些对象。用户可以认为JavaBean 提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
UML 类图
- +表示 public 类型, - 表示 private 类型,# 表示 protected 类型
- 方法的写法: 方法的类型(+、-) ;方法名(参数名: 参数类型):返回值类型
MVC 设计模式
MVC是常用的设计模式之一,将整个程序分为三个层次:视图模型层,控制器层,与 数据模型层。 这种将程序输入输出、数据处理,以及数据的展示分离开来的设计模式 使程序结构变的灵活而且清晰,同时也描述了程序各个对象间的通信方式,降低了程序的耦合性。
JDK 中的主要包介绍(了解)
- java.lang----包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能
- java.net----包含执行与网络相关的操作的类和接口。
- java.io ----包含能提供多种输入/输出功能的类。
- java.util----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
- java.text----包含了一些java格式化相关的类
- java.sql----包含了java进行JDBC数据库编程的相关类/接口
- java.awt----包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。 B/S C/S