javaSE复习
复习javase
1、数据类型
jdk jre jvm
配置环境变量
标识符
关键字
常量+变量
运算符: 算术运算符 比较运算符 赋值运算符 位运算符 逻辑运算符 三元运算符
数据类型:
数据类型转换:java是强类型语言:值的类型必须和变量类型一致
1: 自动类型转换情况1: 高精度变量=低精度数据;
eg: float f=1;
左边float类型的变量f 右边int类型的整数1
编译器会把 4个字节int类型的1 自动转换为4个字节float类型的1.0f 然后赋值
2: 自动类型转换情况2: char/byte/short类型的变量=int常量值;
eg: byte b1=1;
编译器判断1 处在byte范围内,把4个字节int类型的自动转换为1个字节byte类型的1
然后赋值
eg: short s1= 50000; (short取值:-32768到32767)
编译器判断50000不在short范围内,直接报错
3: 强制类型转换: 低精度变量=(低精度变量的类型)高精度数据;
eg: short s2=(short)50000;
int i1=(int)1.1;
编译器强制把8个字节double类型的1.1 转换为4个字节int类型的1 然后赋值
//数据类型精度表:(boolean)byte short (char)int long float double
/*
boolean、byte 1个字节 8位;
short、char 2个字节 16位;
int float 4个字节 32位;
double、long 8个字节 64位
*/
//自动转化三类:
//自动转化类型1,高的精度=低的精度
long l = 1 ;
double d = '1';
//自动转化类型2,byte/short/char 变量 = int 常量值
byte b = 1 ;
//byte占1个字节,8位-127到127
//自动转化类型3,低的精度=(低精度)高的精度
short f = (short) 100000;
//这里输出为负数,因为超过了short的最大值
/*
思考
*/
byte b1 = (int)1.1;
//注意是常量值不是变量,变量必须自己强转
int i1=1;byte b2 = (byte) i1;
short s1 = 1;char c1 = (char) s1;
2、流程控制
学过的内容总结自己的话
计算机所有语言所有概念都是望文生义
流程控制:就是计算机执行程序的流程,一般为从上到下、从左到右。
1.选择结构
if-else
switch:只适用于穷举法,必须把所有可能列举出来
2.循环结构
while
do-while:至少执行一次
for
3: 循环结构
for
while
do while
4: 跳转
break
continue
- ifelse
//2.1 if-else
int a=1;
if(a>0){
System.out.println("a=" + a + "大于0!");
}
if(a>0) //如果执行的代码块只有一个语句 大括号可以省略---不规范
System.out.println("a=" + a + "大于0!");
System.out.println(111);
- switch
//2.2 switch
/*
* switch: 只适用于穷举法: 必须把所有可能的清空列举 不适用范围判断
* switch注意事项:
* 1 switch表达式的值的数据类型仅限于:int+String+enum
* 2 case后面的值不能重复
* 3 只有当所有的case都不正确时 才运行default 与其位置无关
* 4 break的作用是 结束switch结构
* */
//根据月份判断季节: 3 4 5春天 678 夏 9 10 11 秋季 12 1 2 冬季
int month=1;
switch(month){
default:
System.out.println("momnth="+month+"月是火星季!");
break;
case 1:
case 2:
case 12:
System.out.println("momnth="+month+"月是冬季!");
break;
case 3:
case 4:
case 5:
System.out.println("momnth="+month+"月是春季!");
break;
case 6:
case 7:
case 8:
System.out.println("momnth="+month+"月是夏季!");
break;
case 9:
case 10:
case 11:
System.out.println("momnth="+month+"月是秋季!");
break;
}
- while和dowhile的区别
//1 while和dowhile的区别
//while是先判断再执行
//dowhile是先执行再判断::dowhile至少执行一次
int a=-1;
while(a>=0){
System.out.println(a+">=0成立!while");
a--;//迭代语句:按指定的算法更改变量的值
}
a=-1;
do{
System.out.println(a+">=0成立!do---while");
a--;//迭代语句:按指定的算法更改变量的值
}while(a>=0);
- for
//1 for格式
/*
* for(初始化语句;循环条件;迭代语句){
* 循环体
* }
* */
for(int a=1;a<=5;a++){
//System.out.println("a="+a);
}
//2 省略
// for(;;){ //如果条件表达式省略 默认是true 死循环
// System.out.println("111");
// }
//3 执行流程
//初始化语句只执行一次:第一次循环前执行一次
//先执行初始化语句 -》
// 1:判断条件表达式是否成立 不成立结束循环
// 2:条件表达式成立 执行循环体
// 3:循环体执行完 执行迭代语句
// 迭代语句执行完 再次判断条件表达式是否成立 一直循环执行1 2 3步
// 直到1的条件表达式不成立 才结束循环
int i=1;
for(System.out.println("i="+i+"初始化语句!");i<=0; System.out.println("i="+i+"迭代语句!")){
//System.out.println("i="+i+"循环体!");
i++;
}
//4 变量作用范围
int a=1;//1 变量a在for循环外面定义的: 作用于整个for循环 并且在for循环结束后仍然可以访问到
for(int b=1;b<=5;){// 2 变量b在for循环的初始化语句中定义的: 作用于整个for循环 for循环结束后变量消失
int c=1; // 3 变量c在for循环的循环体中定义的:只作用于本次循环
//System.out.println("a="+a+",b="+b+",c="+c);
b++;a++;c++;
}
System.out.println("a="+a);
//案例1:获取1到100内个位数值为1 并且可以被3整除的所有数平均值
// 需要让一个数从值1跑到值2 使用循环
//定义变量记录和 和 个数
int sum1=0,geShu1=0;
for(int n=1;n<=100;n++){
//判断当前n的个位数值为1 并且可以被3整除
if(n%3==0){
//获取个位数
int geWeiShu=n%10;
if(geWeiShu==1){
System.out.println("n="+n+":::满足条件!");
geShu1++;
sum1+=n;
}
}
}
System.out.println("获取1到100内个位数值为1 并且可以被3整除的所有数平均值="+sum1*1.0/geShu1);
3、数组
- 概念
数组:装相同类型 指定个数个数据 的容器
元素:数组中存储的每个数据称为数组的元素
下标/索引: 元素在数组中位置(顺序),通过数组名+下标可以获取元素
关键字:[]
- 特点
1 装多个数据的容器:对象类型
java中把数据按复杂程度分成两种:1 单值数据--八种基本数据类型(值:常量值)
2 复杂数据--多个基本数据有机组合形成的整体(值:对象)
2 元素类型必须相同
3 元素个数固定
4 创建时 必须目前元素类型和元素个数
- 使用
一个数据使用变量记录
多个相同类型的数据使用数组记录
好处:
int age1,age2,age3,age4,age5;
int[] arrAge=new int[5];
数组会自动给装入期中的元素分配下标:下标从0到length-1 通过arrAge[下标] 可以获取指定元素
- 注意事项
1 数组中的元素 不赋值 有默认初始值:值取决于元素的类型
值:此类型的0 boolean是false
2 获取元素时 下标取值为0到length-1 否则:ArrayIndexOutOfBoundsException
- 内容介绍
//等于一个数组装5个int类型的数据
//创建数组时 必须明确:元素类型 元素个数
int[] arr;//定义数组名
arr=new int[5];//new int[5]在内存中创建一个数组 元素类型时int 元素个数时5
// = 让左边的对象名arr指向右边在内存中new的对象
int[] arr2=new int[5];//每new一个 就一个新的对象
//遍历数组:使用for循环
for(int i=0;i<arr.length;i++){
System.out.println("arr["+i+"]="+arr[i]);
}
//遍历数组:使用foreach:简洁for循环
// 优点:简洁
// 缺点:1 不能获取元素的下标
// 2 元素不能增和删
for(int a:arr2){
System.out.println("a="+a);
}
System.out.println(arr[5]);//ArrayIndexOutOfBoundsException: 5
System.out.println(1+1);
//创建数组的三种格式
//格式1: 元素类型[] 对象名=new 元素类型[元素个数];
//不直到元素的具体值:
int[] arr01=new int[3];//数组中的元素有默认值
arr01[0]=19; arr01[1]=29; arr01[2]=18;//给元素赋值
//格式2: 元素类型[] 对象名=new 元素类型[]{值1,值2,值3...};
//知道元素的具体值
int[] arr02=new int[]{1,2,3,4};
//格式3: 元素类型[] 对象名={值1,值2,值3...};
int[] arr03={1,2,3,4};
- 一维数组的要求
//一维数组的要求
//1:遍历
//2:求最大值
arr=new int[]{1,4,5,7,9,0,2,11,4};
int max1=arr[0];//定义变量记录最大值:初始值为第一个元素
for(int i=1;i<arr.length;i++){
//拿max1与所有元素作比较
max1=(max1>arr[i]?arr[i]:max1);
}
//3: 排序
3.1、数组排序:
顺序排序
- 概念
顺序排序:依次拿当前元素何其后面的所有元素做比较
- 图解
- 使用代码模拟打印的效果
int[] arr={9,1,3,6,8,2};//要求从小到大排序
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
//打印的效果
/*
* arr[0]-arr[1] arr[0]-arr[2] arr[0]-arr[3] arr[0]-arr[4] arr[0]-arr[5]
* arr[1]-arr[2] arr[1]-arr[3] arr[1]-arr[4] arr[1]-arr[5]
* arr[2]-arr[3] arr[2]-arr[4] arr[2]-arr[5]
* arr[3]-arr[4] arr[3]-arr[5]
* arr[4]-arr[5]
* */
for(int i=0;i<arr.length-1;i++){//外层for循环记录当前元素的下标:
//System.out.println("当前元素:arr["+i+"]");
for(int j=i+1;j<arr.length;j++){
//arr[i]是当前元素
//arr[j]是当前元素后面的元素
//拿arr[i]和arr[j]比较
System.out.print("arr["+i+"]-arr["+j+"] ");
}
System.out.println();//打印换行
}
- 把打印更改为比较即可
//顺序排序:依次拿当前元素何其后面的所有元素做比较
int[] arr={9,1,3,6,8,2};//要求从小到大排序
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
//把打印更改为比较
for(int i=0;i<arr.length-1;i++){//外层for循环记录当前元素的下标:
for(int j=i+1;j<arr.length;j++){
//arr[i]是当前元素
//arr[j]是当前元素后面的元素
//拿arr[i]和arr[j]比较
if(arr[i]<arr[j]){
int k=arr[i];arr[i]=arr[j];arr[j]=k;
}
}
}
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
冒泡排序
- 核心思想
依次拿相邻运算作比较
-
图解
-
使用java打印出比较过程
int[] arr={1,4,8,9,0,2};
//打印效果
/*
arr[0]-arr[1] arr[1]-arr[2] arr[2]-arr[3] arr[3]-arr[4] arr[4]-arr[5]
arr[0]-arr[1] arr[1]-arr[2] arr[2]-arr[3] arr[3]-arr[4]
arr[0]-arr[1] arr[1]-arr[2] arr[2]-arr[3]
arr[0]-arr[1] arr[1]-arr[2]
arr[0]-arr[1]
*/
//二维图形:两层for循环
//外层for循环控制行数 内层for循环控制本行的列数
//分析:每次比较的两个元素:前一个元素如果是arr[i] 后一个元素就是arr[i+1]
for(int i=0;i<arr.length-1;i++){//共arr.length-1行
for(int j=0;j<arr.length-i-1;j++){//让arr[j]作为前面的元素 arr[j+1]是后面的元素
//打印
System.out.print("arr["+j+"]-arr["+(j+1)+"]\t");
}
System.out.println();
}
- 把打印更改为比较即可
int[] arr={1,4,8,9,0,2};
//打印当前数组
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
//把打印更改为比较即可
for(int i=0;i<arr.length-1;i++){//共arr.length-1行
for(int j=0;j<arr.length-i-1;j++){//让arr[j]作为前面的元素 arr[j+1]是后面的元素
if(arr[j]<arr[j+1]){
int k=arr[j];arr[j]=arr[j+1];arr[j+1]=k;
}
}
}
//打印当前数组
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
冒泡排序和顺序排序的区别
//冒泡排序
for(int i=0;i<arr.length-1;i++){//共arr.length-1行
for(int j=0;j<arr.length-i-1;j++){//让arr[j]作为前面的元素 arr[j+1]是后面的元素
if(arr[j]<arr[j+1]){
int k=arr[j];arr[j]=arr[j+1];arr[j+1]=k;
}
}
}
//顺序排序
for(int i=0;i<arr.length-1;i++){//共arr.length-1行
for(int j=i+1;j<arr.length;j++){//arr[i]作为当前元素 arr[j]作为当前元素后面的元素
if(arr[j]<arr[i]){
int k=arr[j];arr[j]=arr[i];arr[i]=k;
}
}
}
/*
分析:
外层for循环变量i 都是从0开始到length-2:轮数相同 都是length-1轮
内层for循环变量j
冒泡排序:j从0开始到length-i-2 取值:length-i-1
顺序排序:j从i+1开始到length-1 取值:length-i-1
比较的元素:
冒泡排序:arr[j]和arr[j+1]比较
顺序排序:arr[i]和arr[j]比较
*/
3.2、二维数组
- 概念
n维数组:装指定个数个 n-1维数组的容器
注意:一般说的数组::指的是一维数组
二维数组关键字:[][]
- 学习重点
//二维数组要求:
//1 会创建 2 会遍历
//创建二维数组:
//格式1:元素类型[][] 对象名=new 元素类型[n][m];
int[][] arr1=new int[3][4];
//格式2:元素类型[][] 对象名=new 元素类型[][]{{值1,值2,值3..},{值1,值2,值3..},{值1,值2,值3..}};
int[][] arr2=new int[][]{{1},{1,4,6},{1,5},{0,1,2,4,65}};
//格式3:元素类型[][] 对象名={{值1,值2,值3..},{值1,值2,值3..},{值1,值2,值3..}};
int[][] arr3={{1},{1,4,6},{1,5},{0,1,2,4,65}};
//注意1:元素有默认值 int[][] arr1=new int[3][4];
arr1=new int[][]{{1},{1,4,6},{1,5},{0,1,2,4,65}};
System.out.println("arr1="+arr1);
//arr1=[[I@1540e19d 对象类型@16进制内存地址
System.out.println("arr1.length="+arr1.length);
//arr1.length:二维数组arr1中 一维数组的个数
System.out.println("arr1[0]="+arr1[0]);
//arr1[0]:二维数组arr1中 下标为0的一维数组对象
System.out.println("arr1[0].length="+arr1[0].length);
//arr1[0].length:二维数组arr1中 下标为0的一维数组的元素个数
System.out.println("arr1[1][2]="+arr1[1][2]);
//arr1[1][2]:二维数组arr1中 下标为1的一维数组对象中下标为2的元素的值
//遍历二维数组
for(int i=0;i<arr1.length;i++){ //遍历二维数组中的一维数组
for(int j=0;j<arr1[i].length;j++){//遍历当前一维数组arr[i]中的所有元素
System.out.print(arr1[i][j]+(j==arr1[i].length-1?"\n":","));
}
}
3.3数组练习题
/*
* 数组练习题:
* 创建一个装10个int元素的数组: 1 2 3 0 6 7 8 9 9 10 10
* 1 获取数组的次大值:
* 2 数组倒序:
* 3 打印数组:
* 1 3 5 6 4
* *
* ***
* *****
* ******
* ****
* 4 打印数组:
* 1 3 5 6 4
* *
* * *
* * * *
* * * * *
* * * * *
* * * * * *
* 5 扩展题:
* 打印杨辉三角
*
* 1
* 1 1
* 1 2 1
* 1 3 3 1
* 1 4 6 4 1
* 1 5 10 10 5 1
* 1 6 15 20 15 6 1
* */
第四题for循环解法:
private static void print2(int[] arr) {
/* 4 打印数组:
* 1 3 5 6 4 拿所有元素与n比较
* * 6
* * * 5
* * * * 4
* * * * *
* * * * *
* * * * * * 1
*/
//行数:max
//列数:length
//什么时候打印空格 什么时候打印星:::
System.out.println("打印数组:::");
for(int i=0;i<arr.length;i++){
System.out.print((" "+arr[i]+" ")+(i==arr.length-1?"\n":""));
}
//获取最大值
int max=arr[0];
for(int i=1;i<arr.length;i++){
max=max>arr[i]?max:arr[i];
}
//两层for循环
for(int i=max;i>=1;i--){//行数:max行
for(int j=0;j<arr.length;j++){ //拿当前元素arr[j]与i比较
System.out.print(arr[j]>=i?" * ":" ");
}
System.out.println();
}
}
第四题二维数组解法:
public class PrintArrayPlus {
public static void main(String[] args) {
int a[] = { 1,3, 5, 6, 4,1};
char b[][] = new char[6][6];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i]; j++) {
b[i][j]='*';
}
}
// (0,2) (1,2)
//(0,0) (0,1) (0,2) (0,1) (1,1)
//(1,0) (1.1) (1.2) --> (0,0) (1,0)
for (int i = 0; i < b.length; i++) {
for (int j = 0; j < b[0].length; j++) {
System.out.print(b[i][j]);
}
System.out.println();
}
for (int i = 0; i < b[0].length; i++) {
for (int j = 0; j < b.length; j++) {
System.out.print(b[j][b.length-1-i]+"\t");
}
System.out.println();
}
}
}
杨辉三角:
public class YangHuiTriangle {
public static void main(String[] args) {
int a[][] = new int [10][10];
for (int i = 0; i < a.length; i++) {
a[i][0]=1;
a[i][i]=1;
}
for (int i = 2; i < a.length; i++) {
for (int j = 1; j < i; j++) {
a[i][j]=a[i-1][j]+a[i-1][j-1];
}
}
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < i+1; j++) {
System.out.print(a[i][j]+"\t");
}
System.out.println();
}
}
}
4、方法:method
- 概念
方法:类中定义的具有特定功能的代码块
分析: 方法位置:类中
方法实质:代码块{}
方法关键字:()
方法作用:代码的复用
方法意义:一个指定功能
- 格式
修饰符 返回值类型 方法名(参数列表){
方法体
return 返回值;
}
分析:
修饰符:让被修饰者具有一些本来不具有的特征的关键字
修饰符分类:范围修饰符 静态修饰符 常量修饰符 同步修饰符
返回值:方法运行完后给与调用者的结果数据
参数列表:用于方法接受方法运行需要传递的原始数据而定义的变量列表
方法名:标识符:方便调用 和 同类区分
方法体:实现具体功能的代码块
return:关键字:结束方法+把返回值返回给调用者
组成:
方法声明部分: 修饰符 返回值类型 方法名(参数列表)
方法的使用说明书:对方法进行介绍说明
方法体部分: {...}
方法功能具体实现:
- 方法的本质 就是一个功能
- 案例
package com.zhiyou100;
public class Test02Method {
public static void main(String[] args) {
//调用方法 方法才能运行
int n=add1(1,2);
System.out.println("n="+n);
}
//定义方法
public static int add1(int a,int b){
int sum=a+b;
System.out.println("a="+a+":b="+b+":sum="+sum);
return sum;
}
/*
* public:修饰符 可以在整个项目中访问到
* static:修饰符 可以被main方法直接调用
* int: 方法会返回一个int类型的数据
* add1:方法名
* int a,int b:参数列表:方法需要调用者传递两个int类型的数据 用变量a接受第一个数据 变量b接受第二个数据
* int sum=a+b;
System.out.println("a="+a+":"+b+"="+sum);
方法体:实现方法求和功能的代码
* return sum: 结束方法 把sum返回给调用者
* */
}
- 注意事项
package com.zhiyou100;
public class Test02Method {
public static void main(String[] args) {
//调用方法 方法才能运行
int n=add1(1,2);
System.out.println("n="+n);
//n=printAdd(1,1);
//注意2:方法如果有返回值 调用者可以选择接受
add1(1,2);
//注意3:调用方法时传递的参数类型必须和方法的参数列表类型一致
//add1(1,2.1);
//定义方法时的参数列表:::形参 int a,int b
//调用方法时传递的实际数据::实参 1,2
//方法运行时 通过形参的名字来使用实参的值
//注意4:
//基本数据类型作为方法参数:传递的是变量的值 方法体运行完后 实参对应的变量值不会更改
int aa=1;
test1(aa);//代码替换:int a=aa;a++;
//int a=aa;把变量aa的值1复制一份给了变量a 在方法体中对变量a进行修改 和变量aa无关
System.out.println("aa="+aa);//aa=1
//引用数据类型作为方法参数:传递的是对象的内存地址 两个引用指向同一个对象
int[] array=new int[]{1,4,5,7,9,0};
printArr(array);//代码替换:int[] arr=array;arr[0]++;
//int[] arr=array;让数组名arr和array指向同一个数组对象(27行的对象)
test2(array);
printArr(array);
}
public static void test2(int[] arr){
for(int i=0;i<arr.length;i++){
arr[i]++;
}
}
public static void test1(int a){
a++;
}
public static void printArr(int[] arr){
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+(i==arr.length-1?"\n":","));
}
}
//注意1:方法没有返回值:返回值类型用关键字void标识
public static void printAdd(int a,int b){
System.out.println(a+"+"+b+"="+(a+b));
//return ;//如果redtun后面没有返回值 return可以省略
}
//定义方法
public static int add1(int a,int b){
int sum=a+b;
System.out.println("a="+a+":b="+b+":sum="+sum);
return sum;
}
/*
* public:修饰符 可以在整个项目中访问到
* static:修饰符 可以被main方法直接调用
* int: 方法会返回一个int类型的数据
* add1:方法名
* int a,int b:参数列表:方法需要调用者传递两个int类型的数据 用变量a接受第一个数据 变量b接受第二个数据
* int sum=a+b;
System.out.println("a="+a+":"+b+"="+sum);
方法体:实现方法求和功能的代码
* return sum: 结束方法 把sum返回给调用者
* */
}
4.1、方法重载
- 概念:
方法重载:overload:同一个类中几个方法 方法名相同 参数列表不同的现象
- 要求
1 必须是同一个类
2 方法名必须相同
3 参数列表必须不同: 参数个数不同 参数类型不同 参数顺序不同
- 案例
public class Test03OverLoad {
public static void main(String[] args) {
add(1,1);
add(1.1,1);
add(1,1.1);
}
public static void add(int a,int b){
System.out.println("int int:::");
}
public static void add(int a,int b,int c){
System.out.println("int int int::::");
}
public static void add(int a,double b){
System.out.println("int double:::");
}
public static void add(double a,int b){
System.out.println("double int:::");
}
}
- 意义
方法重载:几个功能一致 只是参数列表不同
功能基本一致 满足不同参数列表的需求
5、 面向对象
学习方法
- 联系现实生活
- 内存图
5.1、 OOP概念
OOP:Object Oriented Programming 面向对象编程
一种编程思想(写代码的一种套路 固定模式)
POP:Procedure Oriented Programming 面向过程编程
计算机的两种编程思想
举例:解决吃饭问题
oop: 找饭店 掏钱 说出你的要求 等待厨师做晚饭 吃饭 拍屁股走人
pop: 种米 挖菜 收米 淘米 生火 煮饭 切菜 炒菜 吃饭 刷锅
总结:
pop: 按动作把整个过程分成多个步骤 逐个步骤去完成 最终解决问题
重点:动作
oop: 找具有帮我解决问题功能的对象 指挥对象解决问题
重点:对象
- oop的铁打四步
1 定义类描述一类事物:类中两部分(通过变量表示数据 通过方法表示功能)
2 根据类创建对象
3 给对象的变量赋值
4 调用对象的方法 解决问题
package com.zhiyou100;
public class Test01OOP {
//解决问题:在电脑中模拟人物进行自我介绍
public static void main(String[] args) {
//2 在主方法中:根据Person类创建一个人物对象
//格式:对象类型 对象名=new 对象类型();
// 对象类型 对象名 ---创建引用
// new 对象类型(); ---创建对象
// = 让引用指向对象
Person p1=new Person();
//3 给对象的变量赋值人物的数据
p1.age=65;p1.sex='男';p1.job="作家";p1.name="叶秋雨";
//4 调用对象的方法 解决问题
p1.show();
}
}
//1 通过person类描述人物的类型(人类) 让电脑对人这个类型有个概念
class Person{
// 通过变量表示数据
int age;
String name;
char sex;
String job;
//通过方法表示功能
public void show(){
System.out.println(name+":"+age+":"+sex+":"+job);
}
public void sleep(int second){
System.out.println(name+"休息"+second+"秒!");
}
}
5.2、 类和对象
- 类
1: 类是代码的载体
2: 对一类事物的描述:通过变量表示数据 通过方法表示功能
3: 类是创建对象的模板/图纸
- 对象
1:引用数据类型数据:多个基本数据有机组合形成的整体
2:对象是现实事物在电脑中的模型
3:对象是类的实例
- 关系
对象 是通过类创建的 必须现有类 才有对象
一个类可以创建多个对象
类中定义了那些变量 决定了此类创建的对象有那些数据
类中定义了那些方法 决定了此类创建的对象有那些功能
5.3、 成员
成员:组成的一员
类的成员:类的组成
表示数据的变量---成员变量
表示功能的方法---成员方法
变量的分类:
成员变量:类中定义的变量
局部变量:方法中定义的变量(方法参数列表+方法体中定义的变量)
- 案例
package com.zhiyou100;
public class Test01OOP {
public static void main(String[] args) {
}
}
class Person{
int a;//成员变量
public void test1(int b){//局部变量
int c=1;//局部变量
System.out.println(a+":"+b+":"+c);
}
public void test2(){
System.out.println(a);//此处只能访问成员变量a 不能访问test1方法中定义的局部变量bc
}
}
- 区别
成员变量和局部变量的区别:
概念解释: 成员变量:类中直接定义的变量
局部变量:方法中调用的变量
相同之处: 都是变量 用于记录数据的
不同之处:
1 定义位置不同
成员变量定义在类中 局部变量定义在方法中
2 作用范围不同
成员变量作用域是整个类 局部变量的作用域是当前方法
3 是否有默认值(不赋值 编译器会自动设置值)
成员变量有默认值(值取决于变量的类型) 局部变量必须显式赋值
4 修饰符不同
成员变量可以有 范围修饰符 静态修饰符 final修饰符
局部变量只可以加 fianl修饰符
- 注意
笔试题类型
1 选择题
2 智力题
3 简单题 :xx与yy的区别
第一:先解释 什么是xx 什么是yy
第二:xx与yy的相同之处
第三:分条阐述xx与yy的不同之处
4 编程题
5.4、 构造方法
- 概念
构造方法/构造器 Constructor :用于构建创造对象的方法
- 特点
1 构造方法名字必须和类名相同
2 一个类没有构造方法 编译器默认添加一个无参数的构造方法
3 构造方法没有返回值 不用void标识
4 构造方法的参数列表 一般用于给对象的属性赋值
5 构造方法只能被关键字new调用 用于创建对象 每调用一次就创建一个新的对象
6 构造方法不能被对象调用
- 构造方法和普通方法的区别
第一步:概念
构造方法:类中定义的用于创建对象的方法
普通方法:类中定义的用于描述指定功能 而非创建对象的方法
第二步:相同
都是方法:格式基本相同、都用于表示功能
第三步:不同之处
1 格式不同: 构造方法没有返回值 不用void标识
普通方法必须有返回值类型的标识 没有返回值 用void标识
2 作用不同: 构造方法用于创建对象
普通方法用于描述功能
3 调用不同: 构造方法被关键字new调用 调用一次就创建一个新的对象
普通方法被对象对象 一个对象可以调用多次普通方法
4 是否有默认 如果一个类没有构造方法 编译器默认添加一个无参数的构造方法
普通方法没有默认
5.5、 this
- 概念
this:关键字 在类中表示当前对象(类似于显示中:我自己) 比较特殊的引用
- 案例
package com.zhiyou100;
import java.lang.reflect.Constructor;
public class Test03This{
public static void main(String[] args) {
Test03 t1=new Test03();
t1.test();//this=com.zhiyou100.Test03@1540e19d
System.out.println("t1="+t1);//t1=com.zhiyou100.Test03@1540e19d
Test03 t2=new Test03();
t2.test();//this=com.zhiyou100.Test03@677327b6
System.out.println("t2="+t2);//t1=com.zhiyou100.Test03@677327b6
}
}
class Test03{
public void test(){
System.out.println("this="+this);//哪个对象调用test方法 此处的this指的就是哪个对象
}
}
- this的使用场景1
当成员变量与局部变量重名时 变量名默认指向的是局部变量 通过this.变量名来指向成员变量
注意:方法中调用成员时 前面默认有this.
package com.zhiyou100;
public class Test03This {
public static void main(String[] args) {
//调用方法只能通过对象
Test03 t1=new Test03();
t1.test01();
}
}
class Test03{
int a=2;//成员变量
int b=3;
public void test02(){}
public void test01(){
int a=1;//局部变量
System.out.println("a="+a);//a=1 就近原则
//成员变量与局部变量重名时 变量名默认指向的是局部变量
System.out.println("this.a="+this.a);//通过this.变量来指向成员变量
test02();//this.test02(); 调用成员方法时 前面默认有this.
System.out.println("b="+this.b);//this.b 调用成员变量时 前面默认有this.
}
}
- this的使用场景2
构造方法之间相互调用通过this(参数列表)
注意:this(参数列表) 必须是第一个语句
package com.zhiyou100;
public class Test03This {
public static void main(String[] args) {
new Test03(1,4);
}
}
class Test03{
Test03(int a){
System.out.println("构造方法::Test03(int a)");
}
Test03(int a,int b){
//构造方法之间的调用 是为了代码的复用
this(a);//调用构造方法Test03(int a) //注意this(参数列表) 必须时第一个语句
System.out.println("构造方法::Test03(int a,int b)");
}
}
5.6、 给成员变量赋值的方式
package com.zhiyou100;
public class Test04SetValue {
public static void main(String[] args) {
//1 方式1: 直接在类中给成员变量赋值
// 特点:此类创建的所有对象的此属性初始值都是此值
// 类似于:直接买一个出场为红色的车
Car c11=new Car();//属性:类中定义什么成员变量 此类创建的对象就有什么属性
Car c12=new Car();
Car c13=new Car();
//每个对象都拥有一套只属于自己的成员(属性和方法)
//2 方式2:通过对象.属性给属性赋值
// 特点:必须先创建对象 只能给当前对象的属性赋值
// 类似于:自己刷红漆
// 严厉禁止:属性不安全 无法校验
Car c14=new Car();
c14.number="豫A88888";
//3 方式3:通过构造方法的参数列表给属性赋值
// 特点:对象一创建 属性就有指定的值 只能给当前对象的属性赋值
// 类似于:定制一个红色的
// 鼓励使用
Car c15=new Car(100000);
//4 方式4:通过普通方法的参数列表给属性赋值
// 特点:必须先创建对象 只能给当前对象的属性赋值
// 类似于:拉到4s店改装为红色
// 最常见
Car c16=new Car();
c16.setColor('黑');
c14.show();
c11.show();
c12.show();
c13.show();
c15.show();
c16.show();
}
}
class Car{
char color;
String number;
double money;
String logo="bmw";//方式1: 直接在类中给成员变量赋值
void show(){
System.out.println(color+":"+number+":"+money+":"+logo);
}
Car(){}
Car(double money){//局部变量money
if(money<10000){return;}//数据可控
this.money=money;//通过局部变量给成员变量赋值
}
void setColor(char color){
if(color!='白'&&color!='红'&&color!='黑'){return;}//数据可控
this.color=color;
}
}
5.7、 创建对象内存图
5.8、 static
修饰符: 静态的
可以修饰 成员变量 成员方法 内部类 代码块
-
static修饰的成员:::类成员 (此成员是属于整个类 为整个类的所有对象共有)
-
没有static修饰的成员:::实例成员(此成员是属于对象的 每一个对象都拥有一套只属于自己的实例成员)
-
static修饰的成员变量:::类变量/共享数据
-
static修饰的成员方法:::类方法
-
没有static修饰的成员变量:::实例变量
-
没有static修饰的成员方法:::实例方法
static修饰的变量有什么特点
- 1 类变量不但可以被对象调用 还可以通过类名直接调用
- 2 类变量是共享数据 被所有对象公用
package com.zhiyou100;
//一个源文件可以定义多个类:
//但只能有一个public修饰的类
//并且此类public类必须和源文件名一致
//开发过程中不能这样使用:
public class Test01StaticVariable {
public static void main(String[] args) {
Test01 t1=new Test01();
t1.a=10;
Test01 t2=new Test01();
//每个Test01类型的对象都拥有一个只属于自己的a
System.out.println("a="+t1.a);//10
System.out.println("a="+t2.a);//0
//特点1:类变量可以通过类名直接掉用 还可以通过对象调用
Test01.aa=3;
System.out.println(Test01.aa+":::"+t1.aa);//
//特点2:类变量是共享数据 所有对象公用
t1.aa=4;
System.out.println(t1.aa+":::"+t2.aa+":::"+Test01.aa);
}
}
class Test01{
int a;//成员变量--实例变量
static int aa;//成员变量--类变量/共享数据
}
static修饰的方法有什么特点
- 1 静态方法不但可以被对象可以 还可以被类名直接调用
- 2 静态方法中只能调用类成员 不能调用实例调用
package com.zhiyou100;
public class Test02StaticMethod {
public static void main(String[] args) {
Test02 t1=new Test02();
Test02 t2=new Test02();
t1.show();
t2.show();
//特点1:静态方法不但可以被对象调用 还可以被类名直接调用
t1.showStatic();t2.showStatic();
Test02.showStatic();
//特点2:静态方法中只能调用类成员 不能调用实例成员
// 实例方法中可以调用实例成员和类成员
}
}
class Test02{
int a=1;
static int b=1;
void show(){
System.out.println(a+":::"+b);
showStatic();
}
static void showStatic2(){}
static void showStatic(){
//System.out.println(a);//静态方法中不能调用实例变量
System.out.println(b);
//show();//静态方法中不能调用实例方法
showStatic2();
}
}
静态内存图
5.9、 继承 extends
继承概念
当定义一个新类时 如果新类拥有一个现有的类所有成员 可以让新类从现有的类派生、衍生
新类:::子类
现有的类:::父类
继承格式:::class 子类 extends 父类{}
继承作用:类与类之间创建关系
继承特点
- 1 子类可以继承父类中定义的所有实例成员
- 2 子类可以定义子类特有的成员
- 3 子类不能继承父类的构造方法
- 4 子类可以重新定义父类已有的成员变量:要求变量名相同即可
- 5 子类可以重新定义父类已有的成员方法:重写(override) 要求:方法声明必须和父类完全相同
- 6 java只支持类与类的单继承:一个子类只能有一个直接父类
- 7 一个类没有继承其他类 默认继承Object类
package com.zhiyou100;
public class Test03Extends {
public static void main(String[] args) {
Zi03 zi1=new Zi03();
//特点1: 子类可以继承父类中定义的所有成员
System.out.println(zi1.f1+":"+zi1.f2);//zi03_f1:Fu01_f2
zi1.method01();
zi1.method02();
//特点2:子类可以定义子类特有的成员
System.out.println(zi1.a);
//特点3:子类不能继承父类的构造方法
//zi1=new Zi03(1);
//特点4:子类可以重新定义父类已有的成员变量:要求变量名相同即可
System.out.println(zi1.f1);//11
//特点5:子类可以重新定义父类已有的成员方法:override重写
// 要求:方法名相同 参数列表相同 返回值类型相同
// 方法声明必须和父类一致
zi1.method02();//zi03_method02222
//特点6:java中只支持类与类的单继承:一个子类只能继承一个直接父类
System.out.println(zi1.c);
//特点7:一个类没有继承其他类 默认继承Object类
zi1.toString();
}
}
class Fu033 {//默认继承Object:::lass Fu033 extends Object
int c=1;
}
class Fu03 extends Fu033{
String f1="Fu01_f1";
String f2="Fu01_f2";
void method01(){
System.out.println("Fu01_method01");
}
void method02(){
System.out.println("Fu01_method02");
}
Fu03(){}
Fu03(int i){}
}
class Zi03 extends Fu03{
// String f1="zi03_f1";
int f1=11;//重新定义父类的成员变量
int a=1;//子类特有成员变量
void hehe(){}//子类特有的成员方法
void method02(){//子类重新定义父类的成员方法
System.out.println("zi03_method02222");
}
}
5.10、 重写 override
重写概念
重写:override
子类根据自己的需求重新定义父类已有成员方法
类似于生物中的进化
要求:方法声明必须和父类完全相同
5.11、 super
super概念
super:是关键字 父类的(我父亲的)
this:是关键字 当前对象的(我自己的)
super使用场景
- 参照this
使用场景1:
成员变量和局部变量重名时 变量名默认指向的是局部变量 通过this.变量名来指向成员变量
注意:方法体中涉及的所有成员前面 默认有this.
使用场景2:
构造方法之间的相互调用 通过this(参数列表)
注意:this(参数列表)必须是第一个语句
- super使用
使用场景1:
子类重新定义父类的成员 子类方法中调用此成员默认调用的是子类中的成员
通过super.成员来调用从父类继承而被隐藏的成员
注意:子类方法中调用父类成员 前面默认都super.
使用场景2:
所有的子类构造方法第一个语句默认是super()来调用父类无参数的构造方法
如果父类没有无参数的构造方法 子类构造方法需要显式的通过super(参数列表)来调用父类其他构造方法
package com.zhiyou100;
public class Test04Super {
public static void main(String[] args) {
Zi04 zi1=new Zi04();
zi1.show();
System.out.println(zi1.a+"::"+zi1.e);
}
}
class Fu04{
int b=3;
int a=1;
int c=1;
int e=1;
void hehe(){
System.out.println("fu hehe");
}
//Fu04(){}
Fu04(int b,int c,int e){this.b=b;this.c=c;this.e=e;}
}
class Zi04 extends Fu04{
void hehe(){
System.out.println("zi hehe");
}
int a=2;
void show(){
//子类重新定义父类的成员:子类方法中调用的成员 默认是子类的成员
System.out.println("a="+a);//a=2
hehe();//zi hehe
//子类方法中通过super.成员 来调用父类因被重新定义而被隐藏的成员
System.out.println("super.a="+super.a);//super.a=1
super.hehe();//fu hehe
//注意:子类方法中调用父类成员 前面默认有super.
System.out.println("b="+b);//
}
Zi04(){
super(1,2,2);
}
Zi04(int b,int c,int e){
//super();
//子类构造方法中调用父类构造方法 通过super(参数列表)
super(b,c,e);
//所有子类构造方法的第一个语句默认super()来调用父类无参数的构造方法
}
}
5.12、 final
概念
final是修饰符:
修饰类--最终类
修饰方法--最终方法
修饰变量--常量 (既可以成员变量也可以是局部变量)
特点
- final修饰符类不能被继承
- final修饰符的方法不能被重写
- final修饰的变量是常量 只能赋值一次 、没有默认初始值
package com.zhiyou100;
public class Test05Final {
public static void main(String[] args) {
//final类的特点:final修饰的类不能被继承
Test05 test05=new Test05();
//final变量的特点1: final修饰的变量称之为常量:只能赋值一次
int a=1;
final int b=1;
//final变量的特点2:final修饰的成员变量没有默认值 必须显式赋值
//使用:项目中大量使用身份证号:410195198502222222
//final变量命名规范:所有字母大写 通过下划线分割单词 WO_DE_MING_ZI "苗天宝"
final String ID="410195198502222222";
//作用:增加可读性+简化书写
}
}
//class Test05 extends Test051{ }//报错
final class Test051{}
class Test05{
int a;
final int b=1;//final修饰的成员变量没有默认值 必须显式赋值
//final int b=1;Test05创建的所有对象的b属性 值都是1 而且不能更改
final int c;
Test05(int c){this.c=c;}//这样 就可以根据
void hehe(){}
final void hai(){}
}
class Test052 extends Test05{
Test052(){super(1);}//
void hehe(){}//重写父类的方法
//final void hai(){}//final方法特点:final方法不能被重写
}
//班训:天道酬勤 不忘初衷
5.13、 范围修饰符
概念
关键字:指定被修饰者作用范围的关键字
可以修饰:类+成员变量+成员方法
范围修饰符:public(公共的)+protected(受保护的)+(省略的)+private(私有的)
测试范围
5.14、 继承内存图
5.15、 abstract
abstract概念
abstract:抽象的:修饰符:修饰符类和方法
抽象:笼统 模糊 不清晰 信息不完整
abstract特点
1 抽象方法不能有方法体
2 有抽象方法的类必须是抽象类
3 抽象类不能创建对象 但可以定义引用
4 子类继承抽象类 除非实现所有的抽象方法 否则仍然是抽象类
5 抽象类有构造方法:此构造方法不是用于创建本类对象 而是用于帮助创建子类对象
package com.zhiyou100;
public class Test07Abstract {
public static void main(String[] args) {
//特点1:抽象方法不能有方法体:
//特点2:有抽象方法的类 必须是抽象类
// 注意:抽象类中可以没有抽象方法
//特点3: 抽象类可以定义引用 但不能创建对象
//特点4: 子类除非实现父类所有的抽象方法 否则子类任然是抽象类
//特点5: 抽象类有构造方法 不是用来创建本类对象 而是用于创建子类对象的
Test07 t1;
// t1=new Test07();
new Test07Zi1().show();
}
}
abstract class Test07{
void show(){}
abstract void hai();
}
class Test07Zi1 extends Test07{
Test07Zi1(){
super();
}
void hai(){}//实现父类的所有抽象方法
}
abstract class Test07Zi2 extends Test07{}//子类还是抽象类
/*1 模拟:台灯和灯泡:
台灯有开始和关闭方法 台灯上面可以安装灯泡
灯泡有发亮方法:有两种灯泡 红灯泡和绿灯泡
*
*2 默认:饲养员拿食物喂动物
给狗喂骨头
给兔喂胡萝卜
* */
5.16、 私有化封装
- 概念
封装: 让本类的成员对可信任的类和对象可见 对不可信任的类和对象隐藏
- 代码
package com.zhiyou100;
public class Test01Private {
public static void main(String[] args) {
Test01 t1=new Test01();//其他类中的对象
//t1.age=-1; t1.sex='妖';//此对象t1是不可信任的对象 赋值的范围Test01类无法控制
//不可信任的类或者对象 只能简介的通过get set方法访问封装的成员
t1.setAge(-1);//通过方法 赋值就可控了
System.out.println("age="+t1.getAge());
//开发中:所有的属性必须私有化封装
//get方法格式:public 类型 getXxx();
//set方法格式:public void setXxx(类型 xxx);
}
}
class Test01{
private int age;
char sex;
void show(){
System.out.println("年龄="+age+",性别="+sex);
}
public static void main(String[] args) {
Test01 t1=new Test01();//本类中的对象
t1.age=28;
t1.sex='男';
System.out.println(t1.age+":::"+t1.sex);
}
public void setAge(int age){
if(age<=0||age>=120){return;}
this.age=age;
}
public int getAge(){return this.age;}
}
5.17、 多态(重点)
1 什么是多态
让父类引用指向子类对象
(给子类对象起个父类类型的名字)
(把子类对象伪装成父类类型)
格式:父类引用=子类对象; 等号两边两种形态
多态对象:我们自己方便区分定义的一个概念:::被伪装成父类类型的子类对象
向上转型:让父类引用指向子类对象的过程
2 多态的对象有什么特点
1: 子类特有成员被隐藏
2:子类重新定义的成员变量 显示的是父类中定义的
3:子类重写的方法 使用的是子类中定义的
总结成一句话:::多态对象除了重写的方法 其他和父类对象完全相同
3 什么时候使用多态
使用场景1:
定义方法参数列表时 定义为父类类型 这样就可以传递任意子类类型的对象
- 案例
饲养员给多种动物喂食 喂食完后运动
- 不使用多态实现
package com.zhiyou100;
public class Test031DuoTaiUse {
public static void main(String[] args) {
Dog d=new Dog("哈士奇");
Pig p=new Pig("乔治");
Rabbit r=new Rabbit("兔八哥");
wei(d);
wei(p);
wei(r);
/*
缺点:1 扩展性差
如果有新的动物:需要创建类描述此新类型的动物 并且还需要更改Test031DuoTaiUse 为新类型添加一个wei方法
2 代码复用性差
如果有一百种动物 需要为每种动物都写一个wei方法
* */
}
//由于喂养的动物的类型不同 必须写三个重载的方法 分别指定要喂养的动物的类型
//喂狗
static void wei(Dog d){
System.out.println("饲养员正在喂养动物:"+d.name);
d.yunDong();
}
//喂兔子
static void wei(Pig d){
System.out.println("饲养员正在喂养动物:"+d.name);
d.yunDong();
}
//喂猪
static void wei(Rabbit d){
System.out.println("饲养员正在喂养动物:"+d.name);
d.yunDong();
}
static void wei(Cat d){
System.out.println("饲养员正在喂养动物:"+d.name);
d.yunDong();
}
}
//三种动物
class Dog{
String name;
Dog(String name){this.name=name;}
void yunDong(){
System.out.println("狗"+name+":吃饱了 开始捉老鼠玩!");
}
}
class Pig{
String name;
Pig(String name){this.name=name;}
void yunDong(){
System.out.println("猪"+name+":吃饱了 睡觉!");
}
}
class Rabbit{
String name;
Rabbit(String name){this.name=name;}
void yunDong(){
System.out.println("兔"+name+":吃饱了 游戏!");
}
}
class Cat{
String name;
Cat(String name){this.name=name;}
void yunDong(){
System.out.println("兔"+name+":吃饱了 晒太阳!");
}
}
- 缺点
缺点:1 扩展性差
如果有新的动物:需要创建类描述此新类型的动物 并且还需要更改Test031DuoTaiUse
为新类型添加一个wei方法
2 代码复用性差
如果有一百种动物 需要为每种动物都写一个wei方法
- 使用多态实现
package com.zhiyou100;
public class Test032DuoTaiUse {
public static void main(String[] args) {
Dog2 d=new Dog2("哈士奇");
Pig2 p=new Pig2("乔治");
Rabbit2 r=new Rabbit2("兔八哥");
wei(d);//Animal2 a=d;//多态
wei(p);//Animal2 a=p;//多态
wei(r);//Animal2 a=r;//多态
//多态使用场景1: 定义方法参数列表时 定义为父类类型 这样就可以传递任意子类类型的对象
//优点:1 增加了扩展性
// 有新的类型时 只需要此新类型继承Animal2 实现yunDong方法即可 不需要更改Test032DuoTaiUse类 即可使用wei方法
// 2 增加了代码复用性
// 只需要写一个wei方法 即可实现喂所有的动物
/*
1 定义三个类:Square rect circle
* 写一个方法:根据参数int n的值 返回不同类型的对象:n>0返回正方形 n<0 返回长方形 n==0返回圆
3 定义三个类:Square rect circle
写一个方法返回一个数组:此数组种要装2个圆 2个长方形 2个正方形
* */
}
//4 定义方法时 把参数两边定义为父类类型
static void wei(Animal2 a){
System.out.println("饲养员正在喂养动物:"+a.name);
a.yunDong();
}
}
//1 定义一个父类 描述所有的动物
//抽取所有子类的共同数据和功能
abstract class Animal2{
String name;
Animal2(String name){this.name=name;}
//每种动物都有yunDong方法 但yunDong方法的实现过程 都不同
//由于不知道animal的具体类型 信息不完整 所以父类Animal2的yunDong方法 无法实现
abstract void yunDong();
}
//2 让所以的具体的动物类继承Animal2类
//三种动物
class Dog2 extends Animal2{
Dog2(String name){super(name);}
//3 根据子类的需求实现父类的yunDong方法
//重写父类的抽象方法---实现
void yunDong(){
System.out.println("狗"+name+":吃饱了 开始捉老鼠玩!");
}
}
class Pig2 extends Animal2{
Pig2(String name){super(name);}
void yunDong(){
System.out.println("猪"+name+":吃饱了 睡觉!");
}
}
class Rabbit2 extends Animal2{
Rabbit2(String name){super(name);}
void yunDong(){
System.out.println("兔"+name+":吃饱了 游戏!");
}
}
class Cat2 extends Animal2{
Cat2(String name){super(name);}
void yunDong(){
System.out.println("猫"+name+":吃饱了 晒太阳!");
}
}
- 优点
1 增加了扩展性
有新的类型时 只需要此新类型继承Animal2 实现yunDong方法即可 不需要更改Test032DuoTaiUse类
即可使用wei方法
2 增加了代码复用性
只需要写一个wei方法 即可实现喂所有的动物
使用场景2:
定义类的成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象
- 案例
2 模拟:台灯和灯泡:
台灯有开始和关闭方法 台灯上面可以安装灯泡
灯泡有发亮方法:有两种灯泡 红灯泡和绿灯泡
- 不用多态实现
package com.zhiyou100;
//台灯和灯泡:
//台灯有开始和关闭方法 台灯上面可以安装灯泡
//灯泡有发亮方法:有两种灯泡 红灯泡和绿灯泡
public class Test041DuoTaiUse {
public static void main(String[] args) {
RedBulb r=new RedBulb();
Lamp l=new Lamp();
//给台灯的灯泡属性red赋值
l.red=r;
l.on();
}
/*
* 缺点:
* 1 扩展性差
* 当前台灯只能安装红灯跑和绿灯跑 如果有新的类型的灯泡 需要对台灯类lamp修改
* 添加此灯泡类型的属性才行
* 2 代码复用性差
* Lamp类中定义的灯泡类型 只能接受某一种类型的灯泡对象
* 如果有10种类型的灯泡 就需要定义10个不同类型的成员变量
* */
}
//红灯泡
class RedBulb{
void light(){
System.out.println("红灯泡 发出红光---------------");
}
}
//绿灯泡
class GreenBulb{
void light(){
System.out.println("绿灯泡 发出绿光++++++++++++++");
}
}
//台灯
class Lamp{
//灯泡是台灯的一部分:需要把灯泡定义为台灯的成员变量
RedBulb red;//只能安装红灯泡
GreenBulb green;//只能安装绿灯泡
void on(){//把灯泡作为成员变量传递给on方法
if(red!=null){
red.light();
}
if(green!=null){
green.light();
}
}
//类种的方法可以使用的数据:成员变量+参数列表
//判断数据是不是当前类的一部分 如果是就定义为成员变量 如果不是就定义为参数列表
// void on(RedBulb red){//把灯泡作为参数列表传递
// red.light();
// }
}
- 缺点
* 1 扩展性差
* 当前台灯只能安装红灯跑和绿灯跑 如果有新的类型的灯泡 需要对台灯类lamp修改
* 添加此灯泡类型的属性才行
* 2 代码复用性差
* Lamp类中定义的灯泡类型 只能接受某一种类型的灯泡对象
* 如果有10种类型的灯泡 就需要定义10个不同类型的成员变量
- 使用多态实现
package com.zhiyou100;
//台灯和灯泡:
//台灯有开始和关闭方法 台灯上面可以安装灯泡
//灯泡有发亮方法:有两种灯泡 红灯泡和绿灯泡
public class Test042DuoTaiUse {
public static void main(String[] args) {
RedBulb2 r=new RedBulb2();
GreenBulb2 g=new GreenBulb2();
Lamp2 l=new Lamp2();
//给台灯的灯泡属性red赋值
l.b=r;//多态:Bulb2 b=r;
l.on();
l.b=g;//多态:Bulb2 b=r;
l.on();
}
/*
* 优点:
* 1 扩展性强
* 2 代码复用性强
* */
}
//1 定义父类:抽取所有子类的共同成员
abstract class Bulb2{
//不知道灯泡的具体类型 但只知道有发亮功能 信息不完整 定义为抽象方法
abstract void light();
}
//红灯泡
//2 让子类继承父类
class RedBulb2 extends Bulb2{
//3 子类根据自己的需求 实现父类的抽象方法
void light(){
System.out.println("红灯泡 发出红光---------------");
}
}
//绿灯泡
class GreenBulb2 extends Bulb2{
//3 子类根据自己的需求 实现父类的抽象方法
void light(){
System.out.println("绿灯泡 发出绿光++++++++++++++");
}
}
//台灯
class Lamp2{
//灯泡是台灯的一部分:需要把灯泡定义为台灯的成员变量
//4 定义成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象
Bulb2 b;
void on(){//把灯泡作为成员变量传递给on方法
b.light();
}
}
- 优点
* 1 扩展性强
* 2 代码复用性强
使用场景3:
定义方法返回值类型时 定义为父类类型 这样就可以返回返回任意子类类型的对象
- 案例
// 定义三个类:Square rect circle
// 写一个方法:根据参数int n的值 返回不同类型的对象:
// n>0返回正方形 n<0 返回长方形 n==0返回圆
- 只能通过多态实现
package com.zhiyou100;
import javafx.scene.shape.Circle;
// 定义三个类:Square rect circle
// 写一个方法:根据参数int n的值 返回不同类型的对象:
// n>0返回正方形 n<0 返回长方形 n==0返回圆
public class Test051DuoTaiUse {
public static void main(String[] args) {
Shape01 s=get(1);//多态:Shape01 s=new Square01(1);
}
//此方法的返回值类型写成任意一个具体的形状类型都不合适
//4 定义方法返回值类型时 定义为父类类型 这样就可以返回任意子类类型的对象
public static Shape01 get(int n){
if(n>0){
return new Square01(1);
}
if(n<0){
return new Rect01(2,1);
}
return new Circle01(1);
}
}
//1 定义一个父类 描述所有的形状类型:::抽取所有子类的共同成员
abstract class Shape01{
abstract void show();//信息不完整 show方法体无法实现 定义为抽象方法
}
//2 所有的子类继承父类
class Square01 extends Shape01{
int bianChang;
Square01(int bianChang){this.bianChang=bianChang;}
//3 根据自己的需求实现show方法
void show(){
System.out.println("正方形:边长="+bianChang);
}
}
class Rect01 extends Shape01{
int chang,kuan;
Rect01(int chang,int kuan){this.chang=chang;this.kuan=kuan;}
void show(){
System.out.println("长方形:长="+chang+",宽="+kuan);
}
}
class Circle01 extends Shape01{
int r;
Circle01(int r){this.r=r;}
void show(){
System.out.println("圆形:半径="+r);
}
}
使用场景4:
定义数组的元素类型时 定义为父类类型 这样就可以装任意子类类型的对象
- 案例
3 定义三个类:Square rect circle
写一个方法返回一个数组:此数组种要装2个圆 2个长方形 2个正方形
- 只能通过多态实现
package com.zhiyou100;
// 3 定义三个类:Square rect circle
// 写一个方法返回一个数组:此数组种要装2个圆 2个长方形 2个正方形
public class Test061DuoTaiUse {
public static void main(String[] args) {
Shape02[] array=getArray();
for(Shape02 s:array){
s.show();
}
}
//定义数组的元素类型时 定义为父类类型 这样就可以装任意子类类型的对象
public static Shape02[] getArray(){
Shape02[] arr=new Shape02[6];
arr[0]=new Circle02(1);
arr[1]=new Circle02(2);
arr[3]=new Square02(1);
arr[4]=new Square02(2);
arr[2]=new Rect02(2,1);
arr[5]=new Rect02(3,2);
return arr;
}
}
//1 定义一个父类 描述所有的形状类型:::抽取所有子类的共同成员
abstract class Shape02{
abstract void show();//信息不完整 show方法体无法实现 定义为抽象方法
}
//2 所有的子类继承父类
class Square02 extends Shape02{
int bianChang;
Square02(int bianChang){this.bianChang=bianChang;}
//3 根据自己的需求实现show方法
void show(){
System.out.println("正方形:边长="+bianChang);
}
}
class Rect02 extends Shape02{
int chang,kuan;
Rect02(int chang,int kuan){this.chang=chang;this.kuan=kuan;}
void show(){
System.out.println("长方形:长="+chang+",宽="+kuan);
}
}
class Circle02 extends Shape02{
int r;
Circle02(int r){this.r=r;}
void show(){
System.out.println("圆形:半径="+r);
}
}
总而言之:
1:定义方法参数列表时 定义为父类类型 这样就可以传递任意子类类型的对象
2:定义类的成员变量时 定义为父类类型 这样就可以赋值任意子类类型的对象
3:定义方法返回值类型时 定义为父类类型 这样就可以返回返回任意子类类型的对象
4:定义数组的元素类型时 定义为父类类型 这样就可以装任意子类类型的对象
定义方法的返回值类型、方法参数列表、类的成员变量、数组元素时 ,都定义为父类类型,这样就可以返回、传递、赋值、装任意子类类型的对象
5.18、 多态内存图
5.19、 接口 interface
- 概念
interface:接口
当一个抽象类所有的方法都是抽象方法时 可以把此类定义为接口
如:Shape类
接口使用:和抽象类完全相同
接口作用:给实现类定义规范
关键字:interface
注意:接口与类不是同一种形态
- 特点
1 接口中的成员变量默认修饰符:public static final
2 接口中的成员方法默认修饰符:public abstract
3 接口不是用于创建对象 没有构造方法
4 类"继承"接口--实现 此类称为接口的实现类 关键字implements
5 java支持一个类可以实现多个接口 并且不影响其继承父类
6 接口不能创建对象 但可以定义引用 来指向实现类类型的对象
7 java支持接口之间的多继承
- 代码
package com.zhiyou100;
public interface Test071Interface {
void show();//1 接口中的成员方法默认修饰符 public abstract
int a=1; //2 接口中的成员变量默认修饰符 public static final
//3 接口没有构造方法
//4 子类"继承"接口 成为实现 关键字implements
// 此子类称为接口的实现类
//5 java支持一个类可以实现多个接口 并且不影响其继承父类
// eg:class Test07Zi1 extends Object implements Test071Interface,Inte1{}
//6 接口不能创建对象 但可以定义引用 来指向实现类类型的对象
// eg:Inte1 t=new Test07Zi1();//多态
//7 java支持接口之间的多继承
// interface Inte3 extends Inte1,Inte2{}
}
class Test07Zi1 extends Object implements Test071Interface,Inte1{
public void show(){}
}
interface Inte1{}
interface Inte2{}
interface Inte3 extends Inte1,Inte2{}
class Test07{
public static void main(String[] args) {
Inte1 t=new Test07Zi1();//多态
}
}
- 作用
接口总的作用 为两个有关联的模块之间定义规范
好处:1 增加程序的扩展性
2 提高代码的复用性
3 降低模块之间的耦合度
5.20、package和import
package:包
//class Test01{}
package com.zhiyou100.day06;
public class Test01Package {
static int a=1;
public static void main(String[] args) {
//package的作用:类似于windows的文件夹:对类或者接口的分类管理
// 1 类的全称呼是:包名.类名
System.out.println(Test01Package.a); //syso alt+/自动补齐和提示的快捷键
//没有加包名 默认是本包
System.out.println(com.zhiyou100.day06.Test01Package.a);
//2 package声明包 必须是当前项目的第一个语句
}
}
import:引入/导入
package com.zhiyou100.day06;
import java.io.File;
import java.util.Date;//通过import引入了类全称:在当前源文件中 就可以通过类名来表示此类
import java.lang.*; //注意: 所有源文件默认引入java.lang包的所有类
public class Test02Import {
public static void main(String[] args) {
Date date;
java.util.Date date2;
File file;
java.io.File file2;
//注意: 所有源文件默认引入java.lang包的所有类
System.out.println(111);
}
}
5.21、 instanceof
概念
instanceif是关键字
是运算符
instanceof作用:判断对象的类型
使用:用于判断多态对象的具体类型
5.22、 向下转型
package com.zhiyou100.day06;
public class Test03Instanceof {
public static void main(String[] args) {
//1 创建一个数组 装2个正方形 2个长方形 2个圆形
// 定义数组时 元素类型定义为父类类型 这样就可以装任意子类类型的对象
//2 调用方法 接受数组
Shape01[] array=Test03Instanceof.getArr();//当前类的静态方法
//3 获取每个元素的 获取对象的特有成员
for(Shape01 s:array){
s.show();
// System.out.println("s instanceof Shape01 "+(s instanceof Shape01));
// System.out.println("s instanceof Square01 "+(s instanceof Square01));
// System.out.println("s instanceof Rect01 "+(s instanceof Rect01));
// System.out.println("s instanceof Circle01 "+(s instanceof Circle01));
//Square01 sq=(Square01)s;
//System.out.println("边长="+sq.bianChang);
//向下转型时:ClassCastException: 要转型的类型与具体类型不一致
//避免ClassCastException异常:向下转型时 必须通过instanceof判断 多态对象的具体类型
//通过instanceof判断当前多态对象的具体类型
if(s instanceof Square01){
//向下转型:把多态对象 打回原型
//向下转型格式: 子类引用=(子类类型)多态对象;
Square01 sq=(Square01)s;
System.out.println("边长="+sq.bianChang);
}else if(s instanceof Rect01){
Rect01 sq=(Rect01)s;
System.out.println("chang="+sq.chang+",宽="+sq.kuan);
}else if(s instanceof Circle01){
Circle01 sq=(Circle01)s;
System.out.println("半径="+sq.r);
}
}
}
// 写一个方法返回一个数组
public static Shape01[] getArr(){
Shape01[] arr=new Shape01[6];
arr[0]=new Square01(1);
arr[1]=new Rect01(2, 1);
arr[2]=new Circle01(1);
arr[3]=new Square01(2);
arr[4]=new Rect01(3, 2);
arr[5]=new Circle01(2);//多态::向上转型
return arr;
}
}
//1 定义接口:为所有实现类定义规范
//如果一个类 所有的方法都是抽象的 可以定义为接口
interface Shape01{
void show();
}
//2 根据接口创建实现类
class Square01 implements Shape01{
//特有成员
int bianChang;
Square01(int bianChang){this.bianChang=bianChang;}
//根据实现类需求 实现接口的方法
public void show(){
System.out.println("正方形::边长="+bianChang);
}
}
//2 根据接口创建实现类
class Rect01 extends Object implements Shape01{
//特有成员
int chang,kuan;
public Rect01(int chang, int kuan) {//alt + shift + s
//super();//Object
this.chang = chang;
this.kuan = kuan;
}
//根据实现类需求 实现接口的方法
public void show(){
System.out.println("长方形::chang="+chang+",kuan="+kuan);
}
}
//2 根据接口创建实现类
class Circle01 implements Shape01{
//特有成员
int r;
Circle01(int r){this.r=r;}
//根据实现类需求 实现接口的方法
public void show(){
System.out.println("圆形::半径="+r);
}
}