基础知识
计算机的组成 :
硬件 : 能看得见, 摸得着的电子元器件.
软件 : 存储在硬件中的数据(可以执行) : 指令+数据的集合.
系统软件 : 操作系统 OS, 让用户能够方便的使用电脑硬件.(没有国产OS)
应用软件 : 为了完成某种功能的软件. 学习java目标就是应用软件.
人机交互 : 人通过OS来使用电脑.
GUI :图形化界面
CLI :命令行, 只有一个控制台(console).
在windows中启动控制台 :
Win+r => cmd 回车(动令)
目录 : 用于管理批量的子文件和子目录.
C:\Users\pauliuyou>_
‘>’称为前导符
C:\Users\pauliuyou这是一个目录, 称为当前目录,也称为工作目录.
dir 目录的意思, 作用是列出当前目录下的内容 : 包括子文件和子目录.
切换盘符 : 举例d; 切换到D盘
Md (make directory) 目录名1 目录名2 在当前目录中创建新子目录
把右面的称为命令行参数, 作用是给命令传递进一步的信息数据.
Md 新目录名1 新目录名2
Cd (change directory) 改变当前工作目录.
Cd 目标目录
2个特殊目录 :
- . 点目录表示当前目录
- … 点点目录表示当前目录的上级目录(父目录)
- \ 称为反斜杠
- / 称为斜杠
- \的作用是用于表示父子关系.
- /也可以, 并且在linux系统中必须使用/来表示目录分隔.
路径(path) : 一条路, 这条路的尽头是一个文件或目录.(也称为地址)
Cd MyWork\JavaSE\day01\code
相对路径 : 总是从当前目录为出发点. .\MyWork\JavaSE\day01\code 就是相对路径, 相对路径的前面”./”可以省略
绝对路径 : 以根目录为开始,为出发点的路径 D:\MyWork\JavaSE\day01\code 就是绝对路径. 特点 : 不会出错
- cd/ 直接回到当前盘的根目录
- cd… 返回上一级目录
- cd…/…返回到上两级目录
- Cd /d +路径 可以任意切换目标目录
- exit 退出命令行
计算机语言发展历程
第一代 : 打孔机 面向硬件开发.
第二代 : 汇编语言 面向CPU开发, 缺点: 不能跨CPU
第三代 : C/C++, 面向OS开发, 优点 : 效率高, 缺点 : 不能跨OS
第四代 : java , 面向VM开发, 优点 : 不受OS影响. 缺点 : 相对汇编稍慢
Java的8个特性
- 简单 : 相对于c/c++
- 面向对象 : 相对于面向过程, 面向过程关注问题解决的步骤, 面向对象关注是具有功能的对象
- 分布式 : 基于网络的多主机协助.
- 健壮 : 强类型(所有数据必须有类型), 异常处理, 垃圾收集(内存中应该被释放的空间没有释放. 把空间标记为可用状态就是清理垃圾) GC.
- 安全 : 所有java程序必须通过类加载器
- 跨平台 : 所有java程序中的指令都是面向VM的. 只要有VM, java程序就能执行
- 性能好 : 是编译型比解释型要快.
- 多线程 : 提升服务器的吞吐量, 最大化利用CPU.
Java两种核心机制
- Java虚拟机(Java Virtal Machine)
- 垃圾收集机制(Garbage Collection)
运行java程序的最低要求是 JRE
JRE = JVM + 核心类库
开发java程序必须要求有JDK
JDK = JRE + 开发工具
常用java开发命令
Javac 编译
Java 运行
开发java程序的步骤
- 创建.java源文件
- 编译.java源文件, 生成.class字节码文件
- 运行.class字节码文件
开发程序具体步骤
-
找到d:\MyWork\JavaSE\day01\code目录, 在code目录中右击新建一个文本文件, 改名为Hello.java
-
右击此文本文件, 使用notePad++打开编辑
注意点 : 编辑文件时, 大小写敏感, 所有标点符号必须使用英文半角的标点符号
- 打开命令行窗口, 切换当前工作目录为刚才的code目录中, 并确保刚才编辑的.java文件就在当前目录下.
D:
Cd mywork\javase\day01\code
-
使用命令javac Hello.java 编译源文件, 编译的结果是生成Hello.class字节码文件
-
仍然还是在当前目录中, 使用命令java Hello 执行程序
注意点 : java Hello后面的内容不要加后缀
解决乱码
-
全选并复制所有内容
-
点击菜单”格式” 选中 “以ANSI格式编码”
-
此时会全乱, 把所有内容删除,重新粘贴刚才复制的内容
-
确保右下角的编码方式为ANSI, 如果是utf8重复刚才的步骤
类 : java程序的基本单位
方法 : java程序的基本功能单位
语句 : java程序的最小执行单位
类 {
方法1 {
语句1;
语句2;
……
}
方法2 {
}
….
}
主类 : 包含主方法的类称为主类
非主类 : 不包含主方法的类称为非主类
一个源文件中可以写多个类, 编译以后的结果是每个类都有自己独立的.class文件
但是一个源文件中只能写一个公共类, 非公共类随便, 主类随便
Java程序的执行过程 :
java 主类
java命令一执行, 就会动态地创建一个JVM出来
主类的作用就是告诉JVM加载哪个类并执行, 加载主类以后, 再找到主类的入口方法, 执行入口方法.
主方法一旦执行完毕, JVM销毁, 程序退出
小结第一个程序 :
- Java源文件以“java”为扩展名。源文件的基本组成部分是类(class),如本类中的HelloWorld类。
- 一个源文件中最多只能有一个public类。其它类的个数不限,如果源文件包含一个public类,则文件名必须按该类名命名。
- Java应用程序的执行入口是main()方法。它有固定的书写格式:public static void main(String[] args) {…}
- Java语言严格区分大小写。
- Java方法由一条条语句构成,每个语句以“;”结束。
- 大括号都是成对出现的,缺一不可。
注释
// 单行注释 : 只对当前行有效
/*
多行注释 : 可以给多行文字进行注释, 有头有尾
再来一行, 多行注释不可以嵌套!!
*/
/**
public 是公共的, 是一个形容词, 用于修饰后面的东西.
class 是类, 是一个关键字, 用于声明一个类. 类是java程序的基本单位.
Hello 是类名, 通常类名首字母大写.
类名后面的{}及其中的内容称为 类体
类 = 类头(类签名) + 类体;
主类 : 包含主方法的类就是主类
被public修饰的类 称为 公共类
一个源文件中必须只能有一个公共类, 公共类的类名必须和文件名一致.
*/
public class Hello{
/**
下面的这个东西称为方法, 也称为函数, 是java程序的一个独立的功能单位.
类中包含方法, 方法必须写在类中.
public 是公共的, static 静态的 都是修饰符
void main(String[] args) 方法签名, main称为方法名.
参数后面的一对{}及其中的内容称为方法体.
方法 = 方法签名 + 方法体
方法必须写在类中, 并且不可以嵌套.
此方法称为主方法, 也称为入口方法, 程序总是从main方法开始执行.
写法固定, 必须背会它!!!
*/
public static void main(String[] args){
// 语句 : java程序的最小执行单位, 并且要求必须以;结尾
// 方法中可以包含语句 , 并且可以包含多条语句.
System.out.println(“这里自由发挥,语句1”);
System.out.println(“语句2”);
System.out.println(“语句3”);
System.out.println(“语句4”);
}
/* 方法在同一个类中不可以重复定义!!
public static void main(String[] args) {
System.out.println(“我也是main”);
}*/
public static void method1() {
System.out.println(“method1()…”);
}
}
// 非公共类 : 没有被public修饰的类
class Hello2 { // 非主类, 不包含主方法
public static void test2() {
System.out.println(“test2()…”);
}
}
//public class Hello3 // Hello3不能被public修饰, 因为公共类的类名必须和文件名一致
class Hello3 {
public static void main(String[] args) {
System.out.println(“Hello3 main()…”);
}
}
注意点 : 对于程序的任何修改都必须要重新保存文件, 并重新编译新的.class文件.
NotePad++快捷操作
- Ctrl + a 全选
- Ctrl + c 复制
- Ctrl + v 粘贴
- Ctrl + x 剪切
- Ctrl + z 撤销
- Ctrl + y 重做
- Ctrl + s 保存
- Shift + tab 把选中的内容整体左移
- Tab 把选中的内容整体右移
- Ctrl + l 删除当前行
- Ctrl + d 快速复制当前
JAVA基本语法
关键字 : 在java程序中有特殊含义和作用的单词. 不要直接使用关键字作为标识符
保留字 : 在c/c++中是关键字, 但是在java中目前还不是, 但是将来有可能会成为关键字.
不要直接使用保留字作为标识符
标识符 : 用于标识某个东西的符号(是一个名字)
通常比如标识类, 变量, 方法….
定义合法标识符规则:(必须遵守)
-
组成由26个字母大小写, 0~9, _和$
-
数字不可以开头, 比如3A这个类名不合法, 但是A3就是合法的
-
不可以直接使用关键字和保留字, 但是可以包含关键字和保留字
-
大小写敏感, 最长65535
-
不可以包含空格
java中的名称命名规范(可以不遵守,但是最好遵守)
包名 : 全部小写
类名 : 首字母必须大写, 后面的单词首字母也大写
MyClassName 驼峰命名法
变量,方法名 : 首字母必须小写, 后面的单词首字母大写
myVarName
**常量名 😗*全部大写,单词之间用_隔开
MY_CONST_NAME唯一允许使用_的地方.
编程风格
缩进 : 使用tab
运算符 : 两加都加上空格 4*3/2+5, 4 * 3 / 2 + 5
{}块是行尾风格
变量
内存中的一块区域, 用于保存数据.
此区域必须要命名, 如果没有名字, 我们没有办法定位它.
此区域必须要被特定的数据类型约束, 数据类型可以决定空间大小,并且决定此空间中的数据可以做什么
变量的两个最重要的要素, 就是 数据类型 和 变量名
变量必须先声明, 后使用.
数据类型
Java是一种静态的强类型语言。对于每一个常量、变量、形参、返回值等类型都是非常严格
数据类型作用 :
-
决定了空间的大小.
-
决定了里面的数据可以做什么.
数据类型分类
基本数据类型
(内存区域中保存的是数据本身) 8种
1.数值型:
整数型:
byte:1字节 -128~127
short:2字节 -32768~32768
int:4字节 -20多亿~20多亿
long:8字节 900万亿亿
浮点型:
float:4字节 -1038~1038
double:8字节 10^308
2.字符型:
char:2字节
3.布尔型:
boolean:1字节(true false)
false 为0 true 为真,但是只能用字面量,不能赋值
引用数据类型
内存区域中保存的是别的数据的地址
按照声明的位置划分:
局部变量:
- 方法体{}中
- 方法签名的()中的形参列表
- 代码块{}中
成员变量:
- 在类中,但是在方法和代码块外面
- 有static修饰的成员变量称为静态变量,所有对象共享
- 没有有static修饰的成员变量称为实例变量,每一个对象独立
public class VariableType {
static int a;//成员变量之一:静态变量
int b;//成员变量之一:实例变量
String info;//成员变量之一:实例变量
Student stu;//成员变量之一:实例变量
static{
//静态代码块,后面讲
int c = 1;//局部变量
}
{
//构造代码块,后面讲
int d = 1;//局部变量
}
//(String[] args) 局部变量
public static void main(String[] args) {
int num = 10;//num局部变量,是基本数据类型的局部变量
String str = "hello";//str是局部变量,是引用型局部变量
Student student = new Student("张三");//student是局部变量,是引用型局部变量
}
//int a, int b局部变量
public static int sum(int a, int b){
return a + b;
}
//(int x, int y)局部变量
public void swap(int x, int y){
int temp = x;//局部变量
x = y;
y = temp;
}
}
各种数据类型的使用:
不同的数据使用不同的数据类型来保存, 取决于数据的上限是多少.
变量 : 内存区域中的数据可以修改的量
常量 : 内存区域中的数据不允许修改的量, 包括 字面量(写出来多少就是多少), 和 被final修饰的量:
200, 5.2, false, true, null, ‘a’, “ccc”
赋值符号左侧必须是变量, 如果是常量不可以!!!
范围大的变量是可以接收范围小的量值, 会发生自动数据类型转换
范围小的变量接收范围大的量值时, 必须强制类型转换, 强制类型转换有风险!!!
整数字面量默认使用的类型是int型.
浮点数字面量默认使用的类型是double型(8字节)
数值型范围大小排序, 从大到小:
double > float > long > int > short > byte
> char
任意非long整数变量作运算, 结果总是int型.
多种不同类型的变量混合运算时, 类型会升级为最大的类型
Char 是基本数据类型, 在内存中占用2个字节, 保存的是某个字符的Unicode码值,
它的范围是0~65535. 所以本质上来讲它也是整数, 可以参与整数和浮点数运算.
Char和short,byte不兼容, 互相赋值时, 必须强制类型转换.
Boolean 只允许两个值, 一个true, 一个是false
进制
计算权值以10为底, 这样的数称为10进制数.
10进制没有10, 逢10进1, 最大是9
X进制, 计算权值是以X为底的n次幂. 逢X进一
19 + 1 = 20
二进制 : 计算权值是以2为底的n次幂, 逢2进1
十六进制 : 计算权值是以16为底的n次幂, 逢16进1
进制转换:
十进制 二进制 十六进制
0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
每个十六进制数都可以机械地转化为4个比特的二进制数.
每4个位的二进制数可以转换成一个十六进制数.
0110 => 0x6
0101 1101 => 0x5D
2.变量按照数据类型
分为基本数据类型变量和引用数据类型变量
列出8种基本数据类型, 并写出基本数据类型变量和引用数据类型变量的区别.
1) 基本数据类型 : 内存区域中保存数据本身
数值型
整数:byte short int long char
浮点数:float double
布尔型
boolean
2) 引用(Reference)数据类型 : 内存区域中保存其他数据的地址
地址 : 内存中某个字节的编号. 本质上是一个正整数…
引用变量占用的空间取决于JDK位数 : 如果是32位JDK, 它用4字节整数来保存
如果是64位JDK, 它用8字节整数来保存地址.
地址为0的地址是一个无效地址, 称为null
3 .列出变量使用注意事项
-
先声明, 后使用.
-
变量必须要有数据类型和变量名
-
变量中数据只能在其数据范围内变化.
-
变量有其作用范围, 作用范围由声明语句所隶属的一对{}.
-
同一个作用范围内, 变量不能重复声明(declare)
-
变量必须初始化(出生时进行的赋值)才能使用
int a;
System.out.println(a);
4.判断下列的带( )行的对错
int i1 = 20;
short s1 = i1; (F)
char c1 = 97; (T) char c1 = ‘a’;
char c2 = ‘我’ - ‘你’;(T)
char c3 = (char)(c1 - 32); //可以达到小写变大写的效果(T)
float f1 = i1;(T)
long l1 = 234234239933L;(F) 整数字面量默认使用4字节的int来保存的.
f1 = l1 * 20;(T)
double d1 = .342;
d1 = i1 * f1 * l1;(T) // 混合运算时, 结果类型是范围最大的那个类型
l1 = f1 / 10000;(F)
boolean b1 = (boolean)1;(F)
变量的分类 :
- 按照数据类型来分类
a) 基本数据类型 (保存数据本身)
b) 引用数据类型 (保存对象地址)
2) 按照声明语句的位置来分类
局部变量 : 声明在方法中的变量
范围小, 寿命短.
成员变量 : 声明在类中方法外的变量
范围大, 寿命长
进制
十进制 : 只有0~9, 逢10进1, 一个数计算权值时以10为底n次幂
二进制 : 只有0和1, 逢2进1, 权值计算以2为底
十六进制 : 只有0~F, 逢16进1, 权值计算以16为底
计算机底层的所有数据全是二进制补码.
底层区分正负数使用的是一个数的最高位, 如果最高位为0, 说明这个数是正数
如果最高位符号位值为1, 说明这个数是负数.
补码 :
正数的补码就是自身.
0011 1101 -> 这是一个正数
0x3D -> 3*16+13 = 61, 所以0011 1101就是61
负数的补码 :
由它的相反数全部取反+1得到
1110 1001 -> 这是一个负数, 并且它一定是补码, 负多少?
还原它的相反数就可以.
-1 : 1110 1000
取反 : 0001 0111 => 0x17 => 23
所以1110 1001就是-23
运算符
左移 : 左移一位是一个数*2
右移 : 右移一位是一个数/2
与运算(&) : 对应二进制上有0就是0, 只有全是1的结果才是1
或运算(|) : 对应二进制上有1就是1, 只有全是0结果才是0
整数除法: 注意点 : 小数部分直接丢弃, 所以有可能会有精度丢失!!
取模 % 应用场景
-
M % N结果总是在[0~n-1], 可以让一个未知数落在一个已经的范围内.
-
M % N 结果为0, 说明M可以被N整除
M % N 结果不为0, 说明M不能被N整除.
- M % 2 结果为0, 说明这个数是偶数.
M % 2 结果不为0, 说明这个数是奇数
自增 : 自已就可以变化. 是单目运算.
Int n = 5;
n++; 后加加, 先用后加
等效于 n = n + 1;
++n; 前加加, 先加后用
等效于 n = n + 1;
Int a = 8;
Int b = a++; // b:8, a:9
Int x = 11;
Int y = ++x; // x:12, y:12
赋值运算符 :
- 优先级最低, 所以总是最后执行
- 它是从右向左的逻辑, 右面的值没有确定, 不可以向左走.
- 看到赋值操作心里要紧张, 因为它一定会改变变量的值.
- 累操作, 累加, 累减
- +=, -=, *=, /= 不会引发数据类型的变化, 所以是安全的.
比较运算的结果总是布尔值
- == 比较是否相等
- != 比较是否不等
- 以上和!=可用于所有类型的数据. 但是对象之间, 比较的是对象的地址值.
比较大小的操作 :
>, >=, <, <= 只适用于基本数据类型中的数值型
布尔类型不可以比大小, 还有对象不能比大小.
3 < x < 6
3 < x结果是boolean, 再让boolean和6比大小.
应该写成
3 < x && x < 6
&& 短路与 :
只要有假结果一定是假
|| 短路或 :
只要有真结果一定是真
优先级 :
最高的是. 和(), 最低的是 =
逻辑与算符
& 逻辑与
| 逻辑或
! 逻辑非
&& 短路与
|| 短路或
^ 逻辑异或 (追求的是 “异”)
三元运算符
格式:
(条件表达式)? 表达式1:表达式2;
条件表达式 为true,运算后的结果是表达式1;
条件表达式 为false,运算后的结果是表达式2;
表达式1和表达式2为同种类型
三元运算符与if-else的联系与区别:
1)三元运算符可简化if-else语句
2)三元运算符要求必须返回一个结果。
3)if后的代码块可有多个语句
if-else语句
if语句三种格式:
-
if (条件表达式) {
执行代码块;
} -
if (条件表达式) {
执行代码块;
} else {
执行代码块;
} -
if (条件表达式1) {
执行代码块1;
} else if (条件表达式2) {
执行代码块2;
} else if (条件表达式3) {
执行代码块3;
}
…… else {
执行代码块n;
}
switch语句
switch(变量){
case 常量1:
语句1;
break;
case 常量2:
语句2;
break;
… …
case 常量N:
语句N;
break;
default:
语句;
break;
}
switch语句相关规则
1.switch(表达式)中表达式的返回值必须是下述几种类型之一:byte,short,char,int,String, 枚举;
2.case子句中的值必须是常量,且所有case子句中的值应是不同的;
3.default子句是可任选的,当没有匹配的case时,执行default
4.break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有break,程序会顺序执行到后面第 一个break语句或直接执行到switch结尾(这种现象称为穿透)
2.基本数据类型
8种基本数据类型:
-
数值型
- 整数
byte 1000 0000, 0111 1111 => 0x80, 0x7F
short 1000 0000 0000 0000, 0111 1111 1111 1111 => 0x8000, 0x7FFF
char 0000 0000 0000 0000, 1111 1111 1111 1111 => 0x0000, 0xFFFF
int 1(31个0), 0(31个1) => 0x80000000, 0x7FFFFFFF
long 1(63个0), 0(63个1) => 0x8000000000000000, 0x7FFFFFFFFFFFFFFF
- 浮点数
float
double
-
布尔型
boolean
3.计算下列结果, 分析过程
只需要计算到十六进制形式即可
byte a = 0x6B;
byte b = 0x5D;
// 0110 1011&
// 0101 1101=
// 0100 1001 => 0x49
System.out.println(a & b);
// 0110 1011 |
// 0101 1101 =
// 0111 1111 => 0x7F
System.out.println(a | b);
// 0110 1011 ^
// 0101 1101 =
// 0011 0110 => 0x36
System.out.println(a ^ b);
4.运算符%的作用和实际的应用
%的作用是取余或取模.
1) M % N 结果总是0~N-1, 可以让一个未知数落在一个已知范围内
2) M % N 结果如果为0, 说明M可以被N整除.
3) M % 2 结果如果为0, 说明M是偶数, 如果结果不为0, 说明M是奇数
5.判断:
1)相同字面量十六进制表示的数比十进制要大, 对或错? 为什么?
10以内是相等的. 0x3, 3
其他的情况会大
0x80, 和 80
如果0x80是byte型, 它实际是-128, 80
十六进制本身不承载任何数据类型信息, 只是忠实的反映二进制.
2)if else if else if else 语句中, 如果同时有多个条件都为true, 那么将会有多个语句块被执行,
错, 这是分支, 一定只有一个分支被执行, 不可能执行多个语句块
3)switch case case default 语句中, 如果同时有多个条件都为true, 那么将会有多个语句块被执行
错, case 不允许重复相同.
6.变量的分类法 :
1) 局部变量 : 在方法中声明
范围小, 寿命短
2) 成员变量 : 在类中方法外声明
范围大, 寿命长
循环结构
循环语句功能
在某些条件满足的情况下,反复执行特定代码的功能
循环语句的四个组成部分
初始化部分(init_statement)
循环条件部分(test_exp)
循环体部分(body_statement)
迭代部分(alter_statement)
循环语句分类
while 循环
do/while 循环
for 循环
while循环语句
语法格式
[初始化语句]
while( 布尔值测试表达式){
语句或语句块;
[更改语句;]
}
应用举例
public class WhileLoop {
public static void main(String args[]){
int result = 0;
int i=1;
while(i<=5) {
result += i;
i++;
}
System.out.println("result=" + result);
}
}
do-while循环语句
语法格式
[初始化语句]
do{
语句或语句块;
[更改语句;]
}while(布尔值测试表达式);
应用举例
public class WhileLoop {
public static void main(String args[]){
int result = 0, i=1;
do {
result += i;
i++;
} while(i<=5);
System.out.println("result=" + result);
}
}
注意要点
先执行语句一次,再判断条件
for循环语句
语法格式
for (初始化表达式①; 布尔值测试表达式②⑤⑦; 更改表达式){
语句或语句块③⑥ ;
}
应用举例
public class ForLoop {
public static void main(String args[]){
int result = 0;
for(int i=1; i<=5; i++) {
result += i;
}
System.out.println("result=" + result);
}
}
注意要点
先判断条件,再执行语句
嵌套循环
- 将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for ,while ,do…while均可以作为外层循环和内层循环。
- 实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为false时,才会完全跳出内层循环,才可结束外层的当次循环,开始下一次的循环。
- 设外层循环次数为m次,内层为n次,则内层循环体实际上需要执行m*n次。
嵌套循环练习
九九乘法表
public class NineNine{
public static void main(String[] args){
for(int i = 1;i < 10; i++){
for(int j = 1;j < 10; j++){
int k = i * j;
System.out.print(""+ i + "*" + j + "=" + k + " ");
}
System.out.println("");
}
}
}
空心等腰三角形
//扩展 : 打印高度为n的空心的等腰三角形.
class HomeWork41{
public static void main(String[] args){
int n = Integer.parseInt(args[0]);
for(int i = 0;i < n;i++){
for(int j = 0; j < n - i - 1;j++){
System.out.print(" ");
}
for(int j = 0;j < 2*i+1;j++){
//第n行中间不加空格,所以i<n-1;
//j==0 && j==2i时,两个腰边有*,所以在他们之间打出空格的条件如下
if ((i < n-1) && j > 0 && j < 2*i ){
System.out.print(" ");
}else{
System.out.print("*");
}
}
System.out.println();
}
}
}
输入年、月、日,判断这一天是当年的第几天
先不考虑非法值输入
注:判断一年是否是闰年的标准:
1)可以被4整除,但不可被100整除
2)可以被400整除
例如:1900,2200等能被4整除,但同时能被100整除,但不能被400整除,不是闰年
public class TestExer11{
public static void main(String[] args){
int year = Integer.parseInt(args[0]);
int month = Integer.parseInt(args[1]);
int day = Integer.parseInt(args[2]);
//判断这一天是当年的第几天==>从1月1日开始,累加到xx月xx日这一天
//(1)[1,month-1]个月满月天数
//(2)第month个月的day天
//(3)单独考虑2月份是否是29天(依据是看year是否是闰年)
//2、声明一个变量days,用来存储总天数,直接初始化为day,这样就不用再加day天了
int days = day;
//3、累加[1,month-1]个月满月天数
switch(month){
case 12:
//累加的1-11月
days += 30;//这个30是代表11月份的满月天数
//这里没有break,继续往下走
case 11:
//累加的1-10月
days += 31;//这个31是代表10月的满月天数
//这里没有break,继续往下走
case 10:
days += 30;//9月
case 9:
days += 31;//8月
case 8:
days += 31;//7月
case 7:
days += 30;//6月
case 6:
days += 31;//5月
case 5:
days += 30;//4月
case 4:
days += 31;//3月
case 3:
days += 28;//2月
//4、在这里考虑是否可能是29天
if(year%4==0 && year%100!=0 || year%400==0){
days++;//多加1天
}
case 2:
days += 31;//1月
}
//5、输出结果
System.out.println(year + "年" + month + "月" + day + "日是这一年的第" + days + "天");
}
}
特殊流程控制语句
break 语句
break语句用于终止某个语句块的执行
{ ……
break;
……
}
break语句出现在多层嵌套的语句块中时,可以通过标签指明要终止的是哪一层语句块
class BreakTest2 {
public static void main(String[] args) {
// 循环可以加标签, 标签的命名: 只要是合法标识符就可以
l1 : for (int i = 0; i < 10; i++) {
l2 : for (int j = 0; j < 5; j++) {
System.out.println(" j : " + j);
if (j == 2) {
//break; // 默认中断离我最近的循环.
break l1; // 中断指定标签对应的循环.输出0 1 2以后,循环终止
}
}
System.out.println("i : " + i);
}
}
continue 语句
- continue语句用于跳过某个循环语句块的一次执行
- continue语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环
continue 语句用法
public class ContinueTest {
public static void main(String[] args) {
// continue : 继续, 跳过循环的某次执行, 直接进入下一次执行. 对于循环的破坏力度不大
// 只能用于循环
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
continue; // continue暗含的逻辑, 应该向下走, 但是出现小意外, 导致得跳过.
}
System.out.println("i : " + i);
}
}
}
return 语句
- return:并非专门用于结束循环的,它的功能是结束一个方法。当一个方法执行到一个return语句时,这个方法将被结束。
- 与break和continue不同的是,return直接结束整个方法,不管这个return处于多少层循环之内
特殊流程控制语句说明
- break只能用于switch语句和循环语句中
- continue 只能用于循环语句中
- 二者功能类似,但continue是终止本次循环,break是终止本层循环
- break、continue之后不能有其他的语句,因为程序永远不会执行其后的语句(有就会报错)
- 标号语句必须紧接在循环的头部
方法(method)
方法(函数)的制造环节
方法(method) :
就是函数, 是java程序中的某个独立的功能的体现.
方法必须声明在类中, 并且方法不可以嵌套, 只能并列存在
方法的声明 :
修饰符 返回值类型 方法名(数据类型1 形参1, 数据类型2 形参2, 数据类型3 形参3....) {
语句构成的方法体;
return 返回值;
}
方法 = 方法签名(不执行, 虽然不执行,但是重要, 因为它相当于方法的使用说明书API) + 方法体(执行);
形参 : 形式参数, 在方法声明时的数据, 但是此数据在声明时是没有值的, 没有参数不行, 同时参数的值是多少也没有影响.
形参就是变量, 是某个方法的局部变量.
返回值 : 方法的结果. 如果返回值类型是void, 表示方法没有返回值.
方法的使用环节 :
调用方法 : 方法名(实参列表); // 实参列表必须和形参列表匹配!!!
返回值 : 方法调用本身就是返回值. 返回值的接收只有一次机会.
最简单的方法 : 无返回值, 无参数, 即使是无参, 也不能省略().
无参方法在被调用时, 也不能省略()
方法调用注意点 :
- 没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果在最后一行可以省略 不写。
- 定义方法时,方法的结果应该返回给调用者,交由调用者处理。
- 方法中只能调用方法,不可以在方法内部定义方法。
- 方法的返回值只有一次机会接收, 就是在调用时
- 如果在方法中又调用了方法本身, 称为递归调用
方法代码练习实例:
public class MethodTest {
public static void test() {
System.out.println("test()....");
//return; // 如果方法的返回值为void, 并且在最后有return, 可以省略这个return
}
// 完成一个功能, 两个整数求和. 一个方法可以被多次调用, 并且每次的参数可以不同.
// 方法的每次调用都是一个独立的执行, 互不相干!!!
public static int add(int a, int b) {
System.out.println("add (int a, int b)...");
int c = a + b;
return c; // 返回的是c中的值.
}
public static void main(String[] args) {
System.out.println("main begin");
int x = add(10, 20); // 10称为实参, 20也是实参, 在调用时, 会把10给方法的a, 20给方法的b
//System.out.println(c);
System.out.println(x);
System.out.println(add(50, 80)); // add先执行, println后执行
// 如果方法没有返回值, 禁止接收!!!!
//int y = test(); // 无参方法的调用
test(); // ()如果跟在一个东西后面, 99%可能性是方法调用!! ()是方法的标志.{}是块的标志, []是数组的标志
// 没有返回值的方法, 禁止打印!!!!!
//System.out.println(test());
System.out.println("main end");
}
}
方法的重载
重载(Overload) :
同一个类中, 方法可以有多个重名的, 只要参数不同即可, 这样的一系列方法形成重载.
参数不同 体现为 :
参数的个数不同, 参数的类型不同, 参数的顺序不同.
重载和方法的返回值没有关系 .
如何区分是调用哪个方法, 由实参类型来决定
实参和形参之间是有匹配度的. 优先完全匹配, 再兼容匹配.
方法重载的目的 :
功能类似的参数不同的方法, 用同一个方法名来描述, 对于调用者来说简单, 只需要记一个名字(方法的提供者麻烦)
重载代码练习实例:
public class OverLoadTest {
public static int add(int a, int b) {
System.out.println("add(int a, int b)...");
int c = a + b;
return c;
}
public static int add(int a, int b, int c, int d) {
System.out.println("add(int a, int b, int c, int d)");
int e = a + b + c + d;
return e;
}
public static double add(double a, int b) {
System.out.println("add(double a, int b)");
double c = a + b;
return c;
}
/* 此方法和上面的方法是冲突, 不是重载!!!!
public static double add(double b, int a) {
System.out.println("add(double a, int b)");
double c = b + a;
return c;
}*/
public static double add(int a, double b) {
System.out.println("add(int a, double b)");
double c = a + b;
return c;
}
public static byte add(byte a, byte b) {
System.out.println("add(byte a, byte b)...");
byte c = (byte)(a + b);
return c;
}
public static void main(String[] args) {
System.out.println(add((byte)10, (byte)30));
System.out.println(add(10.2, 30));
System.out.println(add(5, 8));
System.out.println(100); // int
System.out.println("abc"); // String
System.out.println(3.22); // double
System.out.println('A'); // char
System.out.println(true); // boolean
}
}
跨类调用静态方法, 必须使用类.方法
int c = MethodTest.add(a, b); // .表示隶属关系.
System.out.println©;
递归调用
方法调用时,调用方法本身,称为递归调用
递归调用代码实例练习:
public class SimpleTest {
/**
求n的阶乘
求 n * n-1的阶乘, 递归 : 把问题分解成一个小问题和一个子问题.
递归是告诉计算机做什么, 而普通方法则是告诉计算机怎么做.
*/
public static int test(int n) {
//test(n); // 方法调用自身, 这样的调用称为递归调用, 这样的递归会形成无限递归, 死归
if (n <= 1) {
return 1;
}
return n * test(n - 1);
}
public static void main(String[] args) {
System.out.println(test(5));
}
}
家庭记账软件项目
public class FamilyAccount {
public static void main(String[] args) {
// 声明变量保存基本金, 初值是10000
int balance = 10000;
// 声明变量保存记账本, 初值是明细表的表头
String details = "收支\t账户金额\t收支金额\t说 明\n";
// 声明一个用于控制循环的布尔变量, 初值是true
boolean loopFlag = true;
// 写一个循环
do {
// 1) 打印主菜单
System.out.println("-----------------家庭收支记账软件-----------------");
System.out.println("");
System.out.println(" 1 收支明细");
System.out.println(" 2 登记收入");
System.out.println(" 3 登记支出");
System.out.println(" 4 退 出");
System.out.println("");
System.out.print(" 请选择(1-4) : ");
// 2) 通过调用工具类的方法Utility.readMenuSelection(), 获取用户输入的'1'~'4',
// 此方法会返回一个char型的值, 声明变量接收这个char型值.
char ch = Utility.readMenuSelection(); // 它会一直等待用户从键盘输入数字
// 3) 对用户的输入作分支
switch (ch) {
// 4) 如果是'1', 打印记账本字符串
case '1' :
System.out.println(details);
break;
// 5) 如果是'2', 打印"处理收入"
case '2' :
//打印提醒 : 本次收入金额 :
System.out.print("本次收入金额 : ");
//真的调用工具方法获取用户从键盘的实际的输入的整数, 并用变量接收.
int money1 = Utility.readNumber();
//打印提醒 : 本次收入说明 :
System.out.print("本次收入说明 : ");
//真的调用工具方法获取用户从键盘的实际的输入的说明字符串, 并用变量接收.
String string1 = Utility.readString();
// 调整余额, 累加本次收入的金额
balance += money1;
// 拼接本次收入明细
//String info1 = "收入" + 调整后的余额 + 本次收入的金额 + 本次收入说明字符串 + 换行
String info1 = "收入" + "\t" + balance + "\t\t" + money1 + "\t\t" + string1 + "\n";
// 最后把此次收入明细串, 拼接到details的后面
details += info1;
break;
// 6) 如果是'3', 打印"处理支出"
case '3' :
//打印提醒 : 本次支出金额 :
System.out.print("本次支出金额 : ");
//真的调用工具方法获取用户从键盘的实际的输入的整数, 并用变量接收.
int money2 = Utility.readNumber();
//打印提醒 : 本次支出说明 :
System.out.print("本次支出说明 : ");
//真的调用工具方法获取用户从键盘的实际的输入的说明字符串, 并用变量接收.
String string2 = Utility.readString();
// 调整余额, 把支出的金额从余额中累减
balance -= money2;
// 拼接本次支出明细
//String info2 = "支出" + 调整后的余额 + 本次支出的金额 + 本次支出说明字符串 + 换行
String info2 = "支出" + "\t" + balance + "\t\t" + money2 + "\t\t" + string2 + "\n";
// 最后把此次收入明细串, 拼接到details的后面
details += info2;
break;
// 7) 如果是'4', 把控制循环的布尔置为false
case '4' :
System.out.print("确认是否退出(Y/N) : ");
char confirm = Utility.readConfirmSelection();
if (confirm == 'Y') {
loopFlag = false;
}
break;
}
} while (loopFlag);
}
}
面向对象编程
类与对象
类:一类具有相同特性的事物的抽象描述,例如:Student,Circle等
对象:这类事物的一个具体的个体,例如:其中一个学生对象
类是模板,设计图,理解为汽车设计图
对象是实体,理解为实际存在的汽车
面向对象的三大特征:
- 封装
- 继承
- 多态
面向对象 : 关注的是具有功能的对象
面向对象3条主线:
- 类及类的成员的学习
- 三大特性(封装, 继承, 多态)
- 其他关键字
面向对象编程中 : 目标是使用对象来完成功能, 如果对象没有现成的, 制造一个对象来使用.
面向对象程序重点 : 类的设计
类 : 描述复杂的现实世界某种事物, 是一个抽象的,是概念上的.
类就是和普通数据类型一样的数据类型, 只不过是一种复合类型. 类类型或称为引用类型
对象 : 类的某个具体的实体, 也称为实例.
重点 : 类的研究和设计. 类的成员 : 属性, 方法, 构造器
设计类 :
考虑事物的数据部分, 成员(member)变量(属性)来描述.
考虑事物的行为动作, 成员(member)方法来描述.
面向对象代码练习实例
创建类及类的成员
public class Teacher {
// 特征 : 姓名, 年龄, 性别, 身高, 体重, 工资 .....
String name; // 对象属性, 隶属于某个对象, 也称为实例变量.
int age;
String gender;
// 行为 : 吃饭, 上课, 睡觉, 玩, 看电影, 做饭 ......
// 方法 : 修饰符, 返回值类型, 方法名(参数列表) {方法体}
// 对象方法, 隶属于某个对象. 注意点 : 方法千万不要加static修饰符!!!!!
public void eat(String some) {
// 吃什么取决于调用者传的参
System.out.println("老师在吃" + some);
}
public void lesson() {
System.out.println("老师在上课...");
}
// 自我介绍, 用一个字符串描述对象的详细信息, 详细信息就是对象的所有属性值拼接
public String say() {
String str = "姓名 : " + name + ", 年龄 : " + age + ", 性别 : " + gender;
return str;
}
}
创建类的对象
public class TeacherTest {
public static void main(String[] args) {
// 类已经就绪 , 模板就位, 使用模板制造对象
Teacher t = new Teacher(); // 左侧的Teacher是对象的类型.
/*
int n = 200;
n = 30;
System.out.println(n);
*/
t.name = "佟刚";
t.age = 40;
t.gender = "男";
System.out.println(t.name);
System.out.println(t.age);
System.out.println(t.gender);
t.lesson();
t.eat("面包");
String s = t.say(); // 接收返回值
System.out.println(s);
}
}
成员变量
(1)静态变量与实例变量的选择
- 如果这个特征值是整个类的所有对象共享的,那么就声明为静态的;
- 一个对象设置和修改了静态变量,这个类的所有对象都会受到影响
- 所以,建议通过类来修改和访问,而不是通过对象
- 如果这个特征值是每一个对象独立的,那么就声明为非静态的;
- 一个对象设置和修改了和其他对象无关
(2)成员变量与局部变量的异同
相同点:
1、变量的三要素
数据类型、变量名、变量值
2、变量的使用要求
无论是成员变量还是局部变量都要先声明后使用,即我们只能使用声明过的变量,否则编译会报错
不同点:
1、作用域与可见性范围:
-
局部变量有作用域:超出作用域就不能使用
-
成员变量有可见性范围:只要可见就可以通过相应的方式直接操作
-
在本类中,直接访问,但是静态的方法和代码块不能直接访问本类非静态的成员变量
-
在其他类中:静态的建议通过**“类名.”**进行访问,虽然也可以通过“对象名."进行访问
非静态的通过**“对象名."**进行访问
-
2、重名问题
- 同一个作用域中局部变量不能重复声明
- 同一个类中不能成员变量不能重复声明
- 当局部变量与成员变量重名时,要注意区别
- 静态变量:类名.静态变量
- 实例变量:this.实例变量
3、初始化要求
- 局部变量必须手动初始化
- 方法体和代码块中必须有“变量 = 值"的语句,才能使用这个变量
- 方法的形参必须在调用时传入实参为其赋值
- 成员变量
- 如果没有显式初始化,它有默认值
- 也可以进行显式赋值
4、内存位置
- 局部变量:方法调用时在方法对应的栈中
- 成员变量:
- 静态变量:在类对应的方法区中
- 实例变量:在每一个对象的堆中
5、生命周期
- 局部变量:只有该方法或代码块正在执行时,才会存在,执行完立刻消失
- 成员变量:
- 静态变量:只要这个类还在,就一直可以访问,即静态变量与类共存亡
- 实例变量:只要这个对象还在,就可以访问到,即实例变量与对象共存亡,每一个对象的实例变量是独立的
6、修饰符
- 局部变量:没有修饰符,除了final,如果加了final就表示值不能修改,就是常量了
- 成员变量:可以有很多修饰符:public, protected, private ,static, final, transient, volatile等
成员方法
(1)什么是方法
方法(method),又称为函数(function),是指代表一段独立的可复用的功能。
换句话说,我们定义方法/抽取方法的目的是使得某个功能可以被重复使用。
例如:
System.out.println(xx); 这里调用了out对象的println方法,用来输出xx并换行。
Math.sqrt(x):这里调用了Math类的sqrt方法,用来获取x的平方根。
Scanner对象的nextInt():调用Scanner对象的 nextInt(),用来从键盘接收一个整数值
(2)方法的特点和要求
- 方法是必须先声明后使用
- 方法不调用不执行,调用一次执行一次
(3)声明格式
必须在类中,方法外声明
【修饰符】 返回值类型 方法名(【形参列表】){
方法体
}
关于【修饰符】有很多:public, protected, private,static,abstract,final,native,synchronized等等,一个个慢慢学。
(4)分类
- 静态方法:有static修饰的
- 本类中直接调用
- 其他类中,静态的建议通过**“类名.”**进行访问,虽然也可以通过“对象名."进行访问
- 非静态方法:没有static修饰的
- 本类中,只能在本类的非静态方法和代码块中直接调用,同样静态的方法和代码块不能直接访问本类非静态的成员方法
- 其他类中,非静态方法通过**“对象名."**进行访问
(5)参数传递机制:形参与实参
- 方法的参数:方法名后面()里面的东西,就是方法的参数
- 为什么有方法的参数?方法的参数是做什么用的?
方法是代表一个独立的可复用的功能。
那么我们的方法体,就是实现功能的代码。
当我们在实现这个功能的时候,需要一些额外的数据。
例如:设计一个求两个整数和的功能,那么我们就需要两个整数
如何得到这两个整数?
A:在方法体里面从键盘输入
B:让调用者传入这两个整数,至于这两个整数从哪里来,由调用者自己决定
结论:方法的参数是用来接收数据的,调用者给它的数据,用于辅助完成方法的功能 - 参数分为形参和实参
形参:方法声明的()中的是形参,因为在被调用之前,他没有值,只是个形式
int sum3(int a, int b) 没有调用之前,(int a, int b) 是没有值的,是个形式,但是要说明数据类型,
准备接受什么值。
- 实参:方法调用的()中的是实参,因为在调用时,它就有具体的值了。
sum3(1,2) 其中1,2是实参
sum3(i,j) 其中i,j是实参
d.sum3(d.sum3(i,j) ,k); 对于d.sum3(i,j)部分,i和j是实参,
d.sum3(d.sum3(i,j) ,k)部分,第一次调用d.sum3(i,j)的结果是实参之一,k是实参之二 - 实参:给形参赋值的
(6)返回值与return
看方法完成的功能,是否需要调用接收结果。
如果不需要返回结果,那么返回值类型处就写void,在方法体中,如果要提前结束方法,可以使用return;
如果需要返回结果,那么返回值类型处就不能写void,写具体的类型,在方法体中,必须有return 返回值;
(7)方法的参数传递机制
方法的参数传递机制
即实参给形参传了什么值?互相之间的关系是什么样?
(1)实参给形参赋值
(2)实参给形参什么值?
基本数据类型,数据值
引用数据类型,地址值
(3)实参是否会被形参影响
基本数据类型,形参无论怎么修改和实参无关,因为是实参是复制了一份数据给形参。
引用数据类型,形参对象修改了属性/形参数组对象修改了元素,实参会跟着变,因为实参把对象的地址值给形参了,
那么形参和实参就是指向同一个对象。
陷阱:
当形参指向了新对象之后,接下来的操作就和实参无关了
(8)重载
定义:在一个类中出现了,两个或更多个,方法名称相同,形参列表不同的方法就是重载。和返回值类型、权限修饰符无关。
(9)main方法的命令行参数
public class TestCommandParam {
//main方法的(String[] args)形参怎么传实参
//java 类名 参数值1 参数值2 参数值3
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
(10)方法调用的入栈与出栈
每一次方法调用都会在栈中开辟一块独立的空间,用来存储这个方法的局部变量等信息,所以每一次局部变量的值都是全新的。称为“入栈”
每一次方法调用结束之后,都会释放栈空间。称为“出栈”
构造器
构造器也称为构造方法,
本质上是一个方法. 作用 : 在对象创建时进行初始化工作的
构造器的特殊性 :
1) 构造方法名和类名一致, 这是唯一允许使用首字母大写的方法名的方法
2) 它不声明返回值类型, 甚至连void也没有
3) 它不可以被一些关键字修饰, static ,final, abstract…
4) 它不能像普通方法一样随意调用. 只能在创建对象时执行仅有的一次
如果我们在类中并未提供任何构造器, 编译器会自动添加一个缺省构造器 : 无参, 修饰符和类一致, 方法中没有语句.
如果我们在类中提供了构造器, 编译器就不会再自动添加一个缺省构造器了
结论 : 所有类都必须有构造器
构造器重载 : 多个构造器只要参数不同就可以重载
构造器的要求
- 每一个类都有构造器
- 如果一个类没有手动编写构造器,编译器就会自动生成一个无参构造器
- 如果一个类手动编写了构造器,那么编译器就不会自动给你加无参构造器了,如果需要可以自己写
- 构造器的名称必须和类名相同
- 构造器没有返回值类型(包括void)
- 构造器可以重载
构造器的作用和调用
- 构造器的作用是在创建对象时为成员变量初始化用的。
- 我们创建对象时,new后面就是构造器。创建哪个类的对象,就调用哪个类的构造器。
new 类名() 表示调用无参构造创建对象
new 类名(实参) 表示调用有参构造创建对象
示例代码
1、没有编写构造器
示例代码:
class ClassA{
}
public class TestConstructor {
public static void main(String[] args) {
ClassA a = new ClassA();
//调用无参构造,这个无参构造是编译器自动增加的
}
}
2、只编写了有参构造
示例代码:
class ClassB{
private int b;
public ClassB(int b) {
this.b = b;
}
}
public class TestConstructor {
public static void main(String[] args) {
// ClassB b1 = new ClassB();
//报错,编译器不会自动增加无参构造,因为你自己写了有参构造
ClassB b2 = new ClassB(5);//调用有参构造创建对象
}
}
3、既有有参构造又有无参构造
示例代码:
class ClassC{
private int num;
public ClassC(int num) {
this.num = num;
}
public ClassC() {
}
}
public class TestConstructor {
public static void main(String[] args) {
ClassC c1 = new ClassC();//调用无参构造
ClassC c2 = new ClassC(6);//调用有参构造
}
}
4、构造器如果写返回值类型,就不是构造器了
class ClassD{
//不是构造器
public void ClassD(){
System.out.println("普通方法");
}
}
public class TestConstructor {
public static void main(String[] args) {
ClassD d1 = new ClassD();
//调用无参构造
//调用编译器自动生成的无参构造
d1.ClassD();//调用普通方法
}
}
构造器的权限修饰符
(1)当一个类没有编写构造器,编译器会自动产生一个无参构造。这个无参构造的权限修饰符和类一致。
下面的两个类:
- TestConstructor2的无参构造,权限修饰符是public的。
- Demo的无参构造,权限修饰符是缺省的。
public class TestConstructor2 {
}
class Demo{
}
(2)怎么定它的权限修饰符是什么?
看你希望它在哪个范围内能够创建对象
- 如果你只希望这个类在本类中创建对象,即类的外面不能创建对象,那么就是private,例如:单例,枚举等类型
- 如果你只希望这个类在本包中创建对象,出了这个包就不能随意创建对象,那么就是缺省的
- …
如何选择有参构造和无参构造
- 无参构造,创建对象简单,直接new 类名()就可以。特别是后面通过反射或框架帮我们创建对象,那么无参构造都是最最有用的。而且在子类继承时,无参构造也很有用。如果没有极特殊的情况,一个类都要保留它的无参构造。
- 有参构造,如果你在new对象时,就能够为成员变量提供初始值,那么选择有参构造呢,会更方便。
- 你声明的构造器的形式越多,那么代表自己或其他人来创建这个类的对象的方式就越多,就更灵活方便。
对象关联
对象关联 : 一个类的对象关联另外一个类的对象, 一个对象拥有另外一个对象
为什么要关联 : 在当前类中要频繁地使用另外一个类的对象
如何关联 : 在当前类中把另外一个类的对象作为我的属性即可.
属性该如何处理 :
-
- 修改全参构造
-
- 提供get/set方法
-
- 修改say方法
一旦作为属性, 就是成员, 成员意味着大家随便用!!!
代码实例练习(一):
public class Teacher {
private String name;
private int age;
private String gender;
private Computer myComputer; // 对象关联, 被关联的对象
public Teacher() {
}
public Teacher(String name, int age, String gender, Computer myComputer) {
this.name = name;
this.age = age;
this.gender = gender;
this.myComputer = myComputer;
}
public void setMyComputer(Computer myComputer) {
this.myComputer = myComputer;
}
public Computer getMyComputer() {
return myComputer;
}
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 void setGender(String gender) {
this.gender = gender;
}
public String getGender() {
return gender;
}
public String say() {
return "姓名 : " + name + ", 年龄 : " + age + ", 性别 : " + gender + ", 我的电脑 : " + myComputer.say();
}
//public void lesson(Computer com) {
public void lesson() {
System.out.println(name + "老师在使用电脑[" + myComputer.say() + "]上课");
}
public void film() {
System.out.println("老师在使用电脑[" + myComputer.say() + "]在看电影");
}
}
对象双向关联实例一
我们让一个Boy对象关联一个Girl对象,同时,让这个Girl对象也关联这个Boy对象,有点像“你中有我,我中有你”的关系。
public class