目录
低 ------------------------------------> 高
byte,short,char→ int→ long→float→double
10.3.1 形式(先执行,再判断,循环体代码保证最少执行一次)
12.1.6 练习Arrays. copyOf(数组,新的长度)
1 JDK
1.1 JDK概述
JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。
JDK是整个java开发的核心,它包含了:
1.JAVA开发工具(jdk\bin)
2.基础开发库(jdk\jre\lib\rt.jar)
3.基础开发库的源码(jdk\src.zip)
1.1 JDK JRE JVM解释
JDK(Java Development Kit) — Java开发工具包 — JRE+开发工具
开发java程序最小的环境为JDK,所以JDK是JAVA语言的核心
JRE(Java Runtime Environment) — Java运行时环境 — JVM+运行java程序所必需的环境
运行java程序最小的环境为JRE
JVM(Java Virtual Machine)—负责加载.class并运行.class文件
JVM(JAVA虚拟机)将JAVA代码转换为对应的操作系统可以理解的指令,不同的操作系统有不同虚拟机与之对应,同一段代码交给虚拟机之后,虚拟机再转化给操作系统
2 JAVA语法基础
2.1 标识符
标识符可以简单的理解成一个名字。
在Java中,我们需要给代码中的很多元素起名,包括类名、方法名、字段名、变量名等等。我们给对应元素起的名称就被称为标识符,一个正确的标识符需要遵循以下规则:
1. 标识符可以由字母、数字、下划线(_)、美元符($)组成,但不能包含 @、%、空格等其它特殊字符
2. 不能以数字开头。如:123name 就是不合法
3. 标识符严格区分大小写。如: tmooc 和 tMooc 是两个不同的标识符
4. 标识符的命名最好能反映出其作用,做到见名知意。
5. 标识符不能是Java的关键字
2.2 关键字
在Java中,有一些单词被赋予了特定的意义,一共有50个关键字。
这50个单词都是全小写,其中有两个保留字:const和goto。
注意,关键字不能被用作标识符!
需要注意的是,除了上述的50个关键字以外,true,false,null也不可以被用作标识符~
2.3 注释
几乎所有编程语言都允许程序员在代码中输入注释
因为编译器会忽略注释,所以注释并不会影响程序的运行结果。
注释的真正作用是: 它可以向任何阅读代码的人描述或者解释程序的实现思路,如何使用以及其它任何相关信息, 提高代码的可读性,方便后期的维护与复用。
Java的注释有3种:
1. 单行注释: 注释单行内容.
格式: 每行都以”//”开头.
快捷方式: Ctrl+/ 添加注释,同样的快捷键,再按一次取消注释
2. 多行注释:注释多行内容,虽然叫多行注释,也可注释单行内容.
格式: 以” /* ”开头, 以” * / ”结束.
快捷方式: 可以输入” /* ”之后按回车添加注释
3. 文档注释: 一般用来注释类和方法,通过注释内容来记录类或者方法的信息.
格式: 以” /** ”开头。 以” * / ”结尾
快捷方式: 输入 “ /** ” 之后按回车添加注释
2.4 变量
在JAVA中,我们需要记录一些数据
但这些数据的值是不固定的,总在变,我们可以把这些数据理解为变量。
我们通过三个元素来描述变量:变量类型 变量名以及变量值。
定义变量的两种格式:
格式一:声明变量时并且赋值:int age = 18;
格式二:先声明变量:String tel ; 然后给变量赋值:tel = 119;
注意:
1.变量名必须是一个有效的标识符
2.变量名不可以使用java关键字
3.变量名不能重复
2.5 常量
在程序运行过程中,值一直不会改变的量成为常量。
3 数据类型(基本数据类型和引用数据类型)
3.1 基本类型介绍(八种)
变量要保存值,这个值是存在内存中的,所以就需要向内存申请存储空间
java是一个强类型的语言
为了方便内存管理系统根据变量类型更加合理的分配内存空间
会把我们常见的数据,分成不同类型
不同类型分配的内存大小是不同的,这个大小的单位就是字节Byte
拓展:常用的转换关系:
位 bit,来自英文bit,音译为“比特”,表示二进制位。
1 Byte = 8 Bits (1字节 = 8位)
1 KB = 1024 Bytes 1 MB = 1024 KB 1 GB = 1024 MB
3.2 变量交换
需求: 接收用户输入的两个值:假设a=1,b=2,并将这两个变量的值进行互换
创建包: cn.tedu.basic
创建类: TestValueExchage.java
package cn.tedu.basic;
import java.util.Scanner;
/**本类用于练习值交换案例*/
public class TestValueExchange {
//1.创建程序的入口函数main
public static void main(String[] args) {
//2.提示并接受用户在控制台输入的两个整数
System.out.println("请输入要交换的第一个整数:");
int a = new Scanner(System.in).nextInt();
System.out.println("请输入要交换的第二个整数:");
int b = new Scanner(System.in).nextInt();
System.out.println("a的值:"+a);
System.out.println("b的值:"+b);
//3.交换 a b 这两个变量保存的值
int t;//定义一个变量用来辅助值交换
t = a;//把a的值交给t来保存
a = b;//把b的值交给a来保存
b = t;//把t的值交给b来保存
System.out.println("交换后,a的值:"+a);
System.out.println("交换后,b的值:"+b);
}
}
3.3 引用类型
除了基本类型以外的所有类型都是引用类型
目前我们只遇到了String字符串类型,需要用双引号包裹
引用类型是一个对象类型,值是什么呢?
它的值是指向内存空间的引用,就是地址,所指向的内存中保存着变量所表示的一个值或一组值。如:类,接口,数组...
3.4 进制前缀
0b - 标识这是2进制 ,如:0b0101
4 基本类型的类型转换
箭头开始的地方是小类型,箭头指向的地方是大类型
我们此处所指的"大"和"小",指的是对应类型的取值范围,不是字节数哦
4.1 口诀:
小到大,直接转 大到小,强制转 浮变整,小数没
低 ------------------------------------> 高
byte,short,char→ int→ long→float→double
4.2 整数运算溢出
整数运算,类似于一个钟表,转到最大时,再转会回到最小。
5 运算符
5.1 概述
运算符 用于连接 表达式 的 操作数,并对操作数执行运算。
例如,表达式num1+num2,其操作数是num1和num2,运算符是”+”。
在java语言中,运算符可分为5种类型:
算术运算符、赋值运算符、关系运算符、逻辑运算符、位运算符。
根据操作数的不同,运算符又分为单目运算符、双目运算符和三目运算符。
单目运算符只有一个操作数,双目运算符有两个操作数,三目运算符则有三个操作数。
位运算符涉及到二进制位的运算,在java 程序中运用不是很多。
5.2 运算符速查表
数值拆分公式:个位:数值%10, 十位:数值 / 10 % 10 , 百位:数值 / 100 % 10 , ..........
Ctrl+alt+L == 自动格式化代码
拓展补充:
总结1:算术运算符之自增自减运算符
a是操作数,++是自增运算符,- -是自减运算符,自增和自减运算符即可以放在变量的前面,也可以放在变量的后面,例如:a++、++a、a- -、- -a等。
自增(++):将变量的值加1
分前缀式(如++a)和后缀式(如a++)。前缀式是先加1再使用;后缀式是先使用再加1。
自减(- -):将变量的值减1
分前缀式(如- -a)和后缀式(如a- -)。前缀式是先减1再使用;后缀式是先使用再减1。
总结2:逻辑运算符
逻辑运算符连接两个关系表达式或布尔变量,用于解决多个关系表达式的组合判断问题
注意逻辑运算符返回的运算结果为布尔类型
通常,我们用0表示false,用1表示true
与:表示并且的关系
&单与: 1 & 2 ,结果想要是true,要求1和2都必须是true
&&双与(短路与):1 && 2 ,当1是false时,2会被短路,提高程序的效率
或:表示或者的关系
|单或: 1 | 2,结果想要是true,要求1和2只要有一个为true就可以
||双或(短路或):1 || 2,当1是true时,2会被短路,提高程序效率
总结3:优先级控制
当一个表达式包含多个运算符时,就需要考虑运算符的优先级,优先级高的运算符先参与运算,优先级低的运算符后参与运算。在实际的开发中,不需要特别去记忆运算符的优先级别,也不要刻意的使用运算符的优先级别,对于不清楚优先级的地方使用小括号辅助进行优先级管理。
6 分支结构
6.1 概述
顺序结构的程序虽然能解决计算、输出等问题
但不能做判断再选择。对于要先做判断再选择的问题就要使用分支结构
6.2 形式
7 switch结构
7.1 概述
switch case 语句用来判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
当一个case成立,从这个case向后穿透所有case,包括default,直到程序结束或者遇到break程序才结束
7.2 形式
7.3 switch结构的注意事项
- switch 语句中的变量类型可以是: byte、short、int 、char、String(jdk1.7以后支持)
- switch 语句可以拥有多个 case 语句
- 每个 case 后面跟一个要比较的值和冒号,且此值的数据类型必须与变量的数据类型一致
- 当变量值与 case 语句值相等时,开始执行此case 语句的内容,执行完会判断此行代码是否有break,如果有,结束执行,如果没有,会继续向后执行穿透所有case,包括default
- switch 语句可以包含一个 default 分支,该分支一般是写在switch 语句的最后
- 如果在default之前的case有break,则default不会执行
8 循环结构
8.1 for概述
循环结构是指在程序中需要反复执行某个功能而设置的一种程序结构。
它由循环体中的条件,判断继续执行某个功能还是退出循环。
根据判断条件,循环结构又可细分为先判断后执行的循环结构和先执行后判断的循环结构。
8.2 for形式
8.3 for循环执行顺序
我们明明只写了一句打印语句,为什么打印了多个数字呢?
希望通过下图帮你理解for循环的执行顺序:
9 嵌套for循环
9.1 概述
存在至少2层for循环,根据外层的条件,判断里层能否执行
如果能执行,就把里层代码都循环完毕后,再继续判断是否执行外层循环的下一次循环
9.2 嵌套for形式
break与continue
概念
break: 直接结束当前循环,跳出循环体,简单粗暴
break以后的循环体中的语句不会继续执行,循环体外的会执行
注意如果是嵌套for循环,在内层循环遇到了break,只会跳出当前这一层内循环哦
continue: 跳出本轮循环,继续下一轮循环
continue后本轮循环体中的语句不会继续执行,但是会继续执行下轮循环,循环体外的也会执行
10 循环结构2 : while
10.1 形式(先判断,再执行)
10.3循环结构3 : do-while
10.3.1 形式(先执行,再判断,循环体代码保证最少执行一次)
拓展
10.4 三种循环的区别
- for:知道循环次数
- while/do while:当循环次数不确定时
- while:先判断,不符合规则,不执行代码
- do while:代码最少被执行一次,再去判断,符合规则,再次执行代码
- 循环之间都可以互相替代,但是一般最好选择合适的循环结构来完成代码哦~
- continue:跳过本次循环,继续执行下次循环
- break:结束整个循环
10.5 练习:回文数的练习
10.6 求商和余数
package com.cx.ls;
public class abc {
public static void main(String[] args) {
/**
分析:
被除数 / 除数 = 商 ...余数
int a = 100;
int b = 10;
100 - 10 = 90;
90 - 10 = 80;
...
10 - 10 = 0(余数)
*/
//1.定义变量记录被除数
int a = 10;
//2.定义变量记录除数
int b = 3;
//4.定义一个变量来统计相减了多少次
int c = 0;
//3.循环 while
//在循环中,不断的用被除数 - 除数
//只要被除数是大于等于除数的,那么就一直循环
while (a >= b){
a = a - b;
//5.只要减一次,那么统计变量就增加一次
c++;
}
//当循环结束之后a变量的记录的就是余数
System.out.println("余数为:" +a);
//当循环结束之后,c记录的值就是商
System.out.println("商为:" + c);
}
}
11 变量
11.1 概念
可以改变的数,称为变量。在Java语言中,所有的变量在使用前必须声明。
一般通过“变量类型 变量名 = 变量值 ;”这三部分来描述一个变量。如:int a = 3 ;
变量的使用原则:就近原则,即尽量控制变量的使用范围到最小
11.2 局部变量
位置:定义在方法里或者方法的声明上
注意:必须手动初始化来分配内存.如:int i = 5;或者int i; i = 5;
生命周期:随着方法的调用而存在,方法运行完毕就释放了
11.3 成员变量
位置:定义在类里方法外
注意:不用初始化,也会自动被初始化成默认值
生命周期:整个类中,类消失了,成员变量才会释放
11.4 练习:局部变量与成员变量测试
package cn.tedu.oop;
/**本类用于测试变量的使用*/
public class TestVariable2 {
//2.定义成员变量:
//1)位置:类里方法外
//2)无需手动初始化,会自动赋予对应类型的默认值
//3)作用域:在整个类中生效,类消失,变量才会消失
static int count;
//3.变量有一个使用的原则:就近原则
static int sum = 200;
public static void main(String[] args) {
//1.定义局部变量:
//1)位置:在方法里/局部代码块里
//2)必须手动初始化
//3)作用域:在方法/局部代码块中,对应的代码执行完局部变量就被释放
int sum = 100;//定义在方法中的局部变量sum
System.out.println(sum);//变量的就近原则:使用的都是自己附近的变量,100
System.out.println(count);
for (int i = 0; i < 10; i++) {//局部变量i只能在循环中使用
System.out.println(i);
}
//System.out.println(i);//报错:无法引用变量i:i cannot be resolved to a variable
}
}
11.5 方法
11.5.1 概述
被命名的代码块,方法可以含参数可以不含参数,可以提高代码的复用性。
11.5.2 方法定义的格式
11.5.3 方法调用顺序图
顺序执行代码,调用指定方法,执行完毕,返回调用位置
11.6 方法的重载
方法的重载是指在一个类中定义多个同名的方法,但是每个方法的参数列表不同(也就是指参数的个数和类型不同),程序在调用方法时,可以通过传递给他们的不同个数和类型的参数来决定具体调用哪个方法.
*简单记:同一个类中,方法名相同,参数不同的方法。与返回值无关。
拓展 成员变量与局部变量的区别
12 数组
12.1 概念
数组Array,标志是[ ] ,用于储存多个相同类型数据的集合
想要获取数组中的元素值,可以通过脚标(下标)来获取
数组下标是从0开始的,下标的最大值是数组的长度减1
12.2 创建数组
数组的创建方式一般分为动态初始化和静态初始化
- 动态初始化
int[] a = new int[5]; - 静态初始化
int[] b = new int[]{1,2,3,4,5};
int[] c = {1,2,3,4,5};
12.3 创建数组过程分析
程序创建数组 int[] a = new int[5]; 时发生了什么?
- 在内存中开辟连续的空间,用来存放数据,长度是5
- 给数组完成初始化过程,给每个元素赋予默认值,int类型默认值是0
- 数组完成初始化会分配一个唯一的地址值
- 把唯一的地址值交给引用类型的变量a去保存
数组名是个引用类型的变量,它保存着的是数组的地址,不是数组中的数据
12.4 数组的长度
数组的长度用 length属性来表示,数组一旦创建,长度不可改变
数组的长度允许为0
12.5 数组的遍历
遍历:从头到尾,依次访问数组每一个位置,获取每一个位置的元素.形式如下:
我们通过数组的下标操作数组,所以for循环变量操作的也是数组下标
开始:开始下标0 结束:结束下标length-1 如何变化:++
for(从下标为0的位置开始 ; 下标的取值 <= 数组的长度-1 ; 下标++){
循环体;
}`
12.1.1 数组工具类Arrays
12.1.2 Arrays.toString(数组)
把数组里的数据,用逗号连接成一个字符串[值1,值2]
12.1.3 Arrays.sort(数组)
对数组进行排序,对于基本类型的数组使用的是优化后的快速排序算法,效率高
对引用类型数组,使用的是优化后的合并排序算法
12.1.4 练习Arrays.sort(数组)
package cn.tedu.array;
import java.util.Arrays;
/**本类用于测试数组的工具类Arrays*/
public class TestArraysSort {
public static void main(String[] args) {
//1.创建无序数组
int[] a = {21,96,75,23,25};
//底层使用的排序算法是进行优化后的快速排序算法
Arrays.sort(a);//对无序数组进行直接排序
System.out.println(Arrays.toString(a));
}
}
12.1.5 Arrays.copyOf(数组,新的长度)
把数组赋值成一个指定长度的新数组
新数组的长度 大于 原数组, 相当于复制,并增加位置
新数组的长度 小于 原数组, 相当于截取一部分数据
12.1.6 练习Arrays. copyOf(数组,新的长度)
package cn.tedu.array;
import java.util.Arrays;
/**本类用于练习数组的缩容与扩容*/
public class TestArraysCopyOf {
public static void main(String[] args) {
//1.创建数组
int[] from = {1,2,3,4,5};//数组一旦创建,长度不可改变
//2.1 数组的普通复制
/**copyOf()用于完成数组的复制,两个参数:
* 参数1:要复制哪个数组
* 参数2:新数组的长度*/
int[] to = Arrays.copyOf(from, 5);
System.out.println(Arrays.toString(to));
//2.2数组的扩容
/**扩容:给数组扩大容量,新数组的长度>原数组的长度
* 扩容思路:先创建对应长度的新数组,每个位置上都是默认值0
* 然后从原数组中将元素复制到新数组,没有被覆盖的元素还是默认值0*/
int[] to2 = Arrays.copyOf(from, 10);
System.out.println(Arrays.toString(to2));
//2.3数组的缩容
/**缩容:缩小数组的容量,新数组的长度<原数组的长度
* 缩容思路:先创建对应长度的新数组,每个位置上都是默认值0
* 然后从原数组中复制指定个数的元素到新数组中,类似于截取*/
int[] to3 = Arrays.copyOf(from, 3);
System.out.println(Arrays.toString(to3));
//2.4指定首尾截取原数组中的元素
/**copyOfRange()用于完成数组的截取,3个参数:
* 参数1:要截取哪个数组【原数组】
* 参数2:从原数组的哪个下标开始
* 参数3:到原数组的哪个下标结束
* 注意:截取的元素包含开始下标处的元素,不包含结束下标处的元素*/
int[] to4 = Arrays.copyOfRange(from, 2, 4);
System.out.println(Arrays.toString(to4));
}
}
拓展之二维数组
概念
存放数组的数组,也就是说数组里存的还是数组的数据形式
创建二维数组
int[][] a = {{3,5},{7,9},{1,2}};
–创建外部数组,长度是3
–给每个外部数组的位置创建内部数组,每个内部数组的长度是2
–给每个内部数组进行数据初始化
–二维数组生成唯一的地址值
–把地址值交给引用类型变量a来保存
遍历二维数组
for (int i = 0; i < a.length; i++) {//遍历外部数组
for (int j = 0; j < a[i].length; j++) {//遍历内部数组
System.out.println(a[i][j]);//依次打印二维数组中每个元素的值
}
}
打印二维数组中的数据
package cn.tedu.array;
import java.util.Arrays;
/**本类用于打印二维数组中的数据*/
public class TestArrays2 {
public static void main(String[] args) {
//1.创建二维数组
// 3 5
//a[0][0] a[0][1]
// 7 9
//[1][0] a[1][1]
// 1 2 3
//a[2][0] a[2][1] a[2][2]
int[][] a = {{3,5},{7,9},{1,2,3}};
//2.遍历二维数组
for (int i = 0; i < a.length; i++) {
// System.out.println(Arrays.toString(a[i]));
for (int j = 0; j < a[i].length; j++) {
//a[i][j]--根据外部数组的下标和内部数组的下标定位具体的元素
System.out.print(a[i][j]);
}
System.out.println();
}
}
}
13 面向对象基本概念
13.1 面向对象的意义
面向对象的意义在于:
- 将日常生活中习惯的思维方式引入程序设计中。
- 将需求中的概念直观的映射到解决方案中。
- 以模块为中心构建可复用的软件系统。
- 提高软件产品的可维护性和可扩展性。
- 面向对象是当今软件开发中的重要方法。
- 面向对象也是一种编程思想,相对于面向过程,我们的身份可以由原来问题的执行者变为指挥者,进而把生活中很多复杂的问题变得简单化
13.2 面向对象的三大特征
- 封装: 把相关的数据封装成一个“类”组件
- 继承: 是子类自动共享父类属性和方法,这是类之间的一种关系
- 多态: 增强软件的灵活性和重用性
13.3 类和对象
13.3.1 类
- Java语言最基本单位就是类,相当于类型。
- 类是一类事物抽取共同属性与功能形成的。
- 可以理解为模板或者设计图纸。
注意:类在现实世界并不存在,它只是一种对象的数据类型
13.3.2 对象
每个对象具有三个特点:对象的属性,对象的功能和对象的标识。
- 对象的属性用来描述对象的基本特征。
- 对象的功能用来描述对象的可以完成的操作。
- 对象的标识是指每个对象在内存中都有一个唯一的地址值用于与其他对象进行区分,类似于我们的身份证号。
13.3.3 类和对象的关系
- 我们先创建类,再通过类创建出对象
- 我们可以通过一个类创建出多个对象
- 类是抽象的,对象是具体的
13.3.4 对象在内存中的存储
Java把内存分成5大区域,我们重点关注栈和堆。
- 一般来讲局部变量存在栈中,方法执行完毕内存就被释放
- 对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放
- 每个堆内存的元素都有地址值
- 对象中的属性都是成员变量,是有默认值的
TIPS: 栈与队列指的是一种数据的结构。
栈:先进后出(FILO – First In Last Out)
队列:先进先出(FIFO – First In First Out)
对象的创建过程分析:
Phone p = new Phone(); 这句代码,再内存中会发生什么呢?
1.在栈内存中开辟一块空间,存放引用类型Phone类型的变量p
2.在堆内存中开辟一块空间,存放Phone类型的对象
3.要给这个对象进行初始化,比如:String brand = null;
4.当对象准备好以后,会生成一个唯一的地址值,然后将此地址值交给引用类型的变量p来保存
5.如果以后想要操作此对象的各种资源,可以通过p变量保存的地址值找到该对象,比如:p.call(); p.price = 66.6;
13.3.5 练习2:创建多个对象
package cn.tedu.oop;
/**本类用作面向对象入门案例
* 设计手机这一类事物:
* 分析属性:品牌 价格 尺寸 颜色
* 分析功能:打电话 发短信 看直播*/
/**在一个java文件中可以写多个class`,但是,被public修饰的class只能有一个
* 而且要求这个公共类的名字必须与文件的名字保持一致*/
public class TestCreateClass {
public static void main(String[] args) {
//help-findAction 或者 Alt+7
//4.创建手机类的对象p1
Phone p1 = new Phone();
//5.通过手机类对象调用手机类的功能
p1.call();
p1.message();
p1.video();
//6.通过手机类对象打印查看属性值
System.out.println(p1.color);//null
System.out.println(p1.price);//0.0
System.out.println(p1.size);//0.0
System.out.println(p1.brand);//null
//7.创建手机类的第2个对象p2
Phone p2 = new Phone();
//8.通过p2对象,调用Phone类的3个方法
p2.call();
p2.message();
p2.video();
//9.给p2对象的4个属性赋值
p2.brand = "HUAWEI";
p2.color = "中国红";
p2.price = 6666.66;
p2.size = 5.6;
//10.打印查看p2对象的4个属性值
System.out.println(p2.brand);
System.out.println(p2.price);
System.out.println(p2.color);
System.out.println(p2.size);
//11.查看两个对象的地址值
System.out.println(p1);//cn.tedu.oop.Phone@1b6d3586
System.out.println(p2);//cn.tedu.oop.Phone@4554617c
}
}
//1.通过class关键字创建手机类--用来描述手机这一类事物--属性+功能
class Phone{
//2.定义手机类的属性--用成员变量来描述--位置:类里方法外
String brand;//品牌
double price;//价格
double size;//尺寸
String color;//颜色
//3.定义手机类的功能--用方法来描述--格式:修饰符 返回值类型 方法名(参数列表){方法体}
public void call(){
System.out.println("正在打电话~");
}
public void message(){
System.out.println("正在发短信!");
}
public void video(){
System.out.println("正在看直播~");
}
}
p2.brand = “HUAWEI”;
就是先到栈内存中找到p2中保存的唯一的地址值
然后根据地址值找到对应的Phone对象,并对其对应的属性值进行修改
p2.eat();
也是先到栈内存中找到p2中保存的唯一的地址值
然后根据地址值找到对应Phone对象,执行Phone对象的eat()方法
13.4 封装
13.4.1 概述
封装是隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式,比如类和方法
好处:
- 提高安全性
- 提高重用性
13.4.2 private关键字
是一个权限修饰符 ,可以用来修饰成员变量和成员方法.被私有化的成员只能在本类中访问。
12.4.3练习:封装的必要性
package cn.tedu.oop;
/*本类用于测试封装的必要性*/
public class TestPrivate1 {
public static void main(String[] args) {
//3.创建用户类的对象
User u = new User();
//4.修改对象的属性值
u.name = "李逵";
/*需要封装属性,如果不封装的话,就可以直接修改属性的值,不安全*/
//u.money = 999999999;
//5.查看修改后的属性值
System.out.println(u.name);
//System.out.println(u.money);
//6.4调用两个方法修改和查看属性值
u.setMoney(8888888.88);
System.out.println(u.queryMoney());
}
}
//1.创建一个用户类User
class User{
//2.定义用户类的属性
String name;
//6.1封装属性--通过private关键字封装属性
private double money = 10000;
//6.2提供方法1:查询当前账户的余额
public double queryMoney(){
/*后续可以添加权限校验的操作*/
return money;
}
//6.3提供方法2:修改当前账户的余额
public void setMoney(double money){
/*后续可以添加权限校验的操作*/
/*当本类的成员变量与局部变量同名时
可以使用this关键字指定本类的成员变量*/
this.money = money;
}
}
TIPS:如何封装?封装后的资源如何访问?
我们可以使用private关键字来封装成员变量与方法
如何访问私有资源?
关于成员变量:
setXxx – 对外提供公共的设置值方式
getXxx – 对外提供公共的获取值方式
关于成员方法:
把私有方法放在公共方法里供外界调用即可
13.5 访问控制符
用来控制一个类,或者类中的成员的访问范围。
TIPS:default是表示不写修饰符,默认,如果写default单词来修饰会报错
拓展 匿名对象
没有名字的对象,是对象的简化表示形式。
使用场景:
当被调用的对象只调用一次时(多次会创建多个对象浪费内存)
Demo d = new Demo();
d.sleep();
d.game();
//这个d就是对象的名字。
也可以写成:
new Demo().show();//创建了一个对象调方法
new Demo().game();//又创建了一个对象调方法。
14 构造方法
14.1 概念
构造方法是一种特殊的方法,它是一个与类同名且没有返回值类型的方法
构造方法的主要功能就是完成对象创建或者初始化
当类创建对象(实例化)时,就会自动调用构造方法
构造方法与普通方法一样也可以重载.
创造对象的时候,虚拟机会自动调用构造方法,作用是给成员变量继续初始化的。
14.1.2 形式
与类同名,且没有返回值类型,可以含参也可以不含参
关于构造函数怎么记忆:
- 特点:方法名与类名相同,且没有返回值类型
- 执行时机:创建对象时立即执行
- 默认会创建无参构造,但是,如果自定义了含参构造,默认的无参构造会被覆盖,注意要手动添加哦
14.2 构造代码块与局部代码块
14.2.1形式:
{ 代码… }
14.2.2 构造代码块的特点
- 位置: 在类的内部,在方法的外部
- 作用: 用于抽取构造方法中的共性代码
- 执行时机: 每次调用构造方法前都会调用构造代码块
- 注意事项: 构造代码块优先于构造方法加载
14.2.3局部代码块
- 位置: 在方法里面的代码块
- 作用: 通常用于控制变量的作用范围,出了花括号就失效
- 注意事项: 变量的作用范围越小越好,成员变量会存在线程安全的问题
14.2.4 创建对象的流程
Person p = new Person();//短短这行代码发生了很多事情
1.把Person.class文件加载进内存
2.在栈内存中,开辟空间,存放引用变量p
3.在堆内存中,开辟空间,存放Person对象
4.对成员变量进行默认的初始化
5.对成员变量进行显示初始化
6.执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)
7.堆内存完成
8.把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值
15 继承
1概念
继承是面向对象最显著的一个特征
继承是从已有的类中派生出新的类,新类能吸收已有类的数据属性和行为,并扩展新的能力.
Java继承是会用已存在的类的定义作为基础建立新类的技术
新类的定义可以增加新的数据或者新的功能,也可以使用父类的功能,但不能选择性的继承父类(超类/基类)
这种继承使得复用以前的代码非常容易,能够大大的缩短开发的周期,降低开发费用.
1.2 特点
- 使用extends关键字来表示继承关系
- 相当于子类把父类的功能复制了一份
- Java只支持单继承
- 继承可以传递(爷爷/儿子/孙子这样的关系)
- 父类的私有成员由于私有限制访问,所以子类不能使用父类的私有资源
- 继承多用于功能的修改,子类可以在拥有父类功能的同时,进行功能拓展
- 像是is a的关系
2 super
我们可以把super看作是父类的对象:Father super = new Father();
1.当父类的成员变量与子类的变量同名时,使用super指定父类的成员变量
2.使用super在子类构造方法的第一行调用父类构造方法的功能
super();–调用的是父类的无参构造
super(参数);–调用的是父类对应参数的构造方法
注意:在构造方法里,出现的调用位置必须是第一行
3 方法重写Override
- 继承以后,子类就拥有了父类的功能
- 在子类中,可以添加子类特有的功能,也可以修改父类的原有功能
- 子类中方法的签名与父类完全一样时,会发生覆盖/复写的现象
- 注意: 父类的私有方法不能被重写
- 重写的要求:两同两小一大
两同:方法名 参数列表 要完全一致
两小:
子类返回值类型小于等于父类的返回值类型(注意此处说的是继承关系,不是值大小)
子类抛出异常小于等于父类方法抛出异常
一大:子类方法的修饰符权限要大于等于父类被重写方法的修饰符权限
4. 拓展
4.1 继承的好处与坏处
继承的好处
提高了代码的复用性(多个类相同的成员可以放在同一个类中)
提高了代码的维护性(如果方法的代码需要修改,只修改一处即可)
继承的坏处
继承让类与类建立了关系,类的耦合性增强
当父类发生变化时,子类实现也不得不跟着变化,削弱了子类的独立性
4.2 this与super的区别
this: 代表本类对象的引用
我们可以把this看作是Cat this = new Cat();
super:代表父类存储空间的标识,可以理解成父类对象的引用
可以把super看作是Father super = new Father();
this关键字指向调用该方法的对象
一般我们是在当前类中使用this关键字
所以我们常说this代表本类对象的引用
注意:super的使用前提是继承,没有父子类关系,就没有super
注意:this调用构造方法或者super调用构造方法,都必须出现在构造方法的第一行
注意:如果父类没有无参构造,需要手动在子类构造方法的第一行调用其他的含参构造
拓展:如果子类重写了父类的方法以后,可以使用super.方法名(参数列表)来调用
4.2 重载Overload 与重写Override的区别
重载:在一个类中的现象:同一个类中,存在方法名相同,参数列表不同的方法
重写:是指建立了继承关系以后,子类对父类的方法不满意,可以重写,遵循两同两小一大原则
重载的意义:是为了外界调用方法时方便,不管传入什么样的参数,都可以匹配到对应的同名方法
重写的意义:在不修改源码的情况下,进行功能的修改与拓展(OCP原则:面向修改关闭,面向拓展开放)
16 static
1.1 概念
是java中的一个关键字
用于修饰成员(成员变量和成员方法)
1.2 特点
1.static可以修饰成员变量和方法
2.被static修饰的资源称为静态资源
3.静态资源随着类的加载而加载,最先加载,优先于对象进行加载
4.静态资源可以通过类名直接调用,也被称作类资源
5.静态被全局所有对象共享,值只有一份
6.静态资源只能调用静态资源
7.静态区域内不允许使用this与super关键字
static的注意事项总结:
- 静态方法中,只能访问静态。
- 非静态方法可以访问所有。
- 静态方法中没有this与super关键字。
练习:static静态调用关系
package cn.tedu.oopstatic;
/*本类用于测试静态的调用关系*/
/*总结:
* 1.普通资源既可以调用普通资源,也可以调用静态资源
* 2.静态资源只能调用静态资源*/
public class TestStatic2 {
}
//1.创建老师类
class Teacher{
//2.定义普通属性与方法
String name;
public void teach(){
System.out.println("正在授课中...");
/*1.普通资源能否调用静态资源?--可以!!!*/
System.out.println(age);
ready();
}
//3.定义静态属性与方法
static int age;
public static void ready(){
System.out.println("正在备课中...");
/*2.静态资源能否调用普通资源?--不可以!*/
//System.out.println(name);
//teach();
}
public static void eat(){
System.out.println("正在吃饭中...");
/*3.静态资源能否调用静态资源?--可以!*/
System.out.println(age);
ready();
}
}
2 静态代码块、构造代码块、局部代码块
2.1 静态代码块格式
静态资源随着类的加载而加载,并且只被加载一次,一般用于项目的初始化
特点: 被static修饰,位置在类里方法外
2.2 三种代码块的比较
- 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
- 构造代码块:在创建对象时会自动调用,每次创建对象都会被调用,提取构造共性
- 局部代码块:方法里的代码块,限制局部变量的范围
练习:几种代码块的关系
package cn.tedu.oopstatic;
/*本类用于学习静态代码块*/
/*执行顺序:
* 静态代码块->构造代码块->构造方法【对象创建成功】->局部代码块*/
public class TestStaticBlock {
public static void main(String[] args) {
//6.创建对象进行测试
Person p = new Person();
Person p2 = new Person();
//7.触发局部代码块
p.play();
}
}
//1.创建Person类
class Person{
//8.创建静态代码块
/*位置:类里方法外
* 执行时机:静态代码块也属于静态资源,随着类的加载而加载,优先于对象加载
* 并且静态资源只会加载一次
* 作用:用于加载那些需要第一时间就加载,并且只加载一次的资源*/
static{
System.out.println("我是静态代码块");
}
//2.创建构造代码块
/*位置:类里方法外
执行时机:每次创建对象时被触发,并且优先于构造方法执行
作用:用于提取所有构造方法的共性功能*/
{
System.out.println("我是构造代码块");
}
//5.创建构造方法
public Person(){
System.out.println("我是无参构造");
}
//3.创建普通方法
public void play(){
System.out.println("我是一个普通方法");
//4.创建局部代码块
/*位置:方法里
* 执行时机:执行本局部代码块所在的方法时才会执行
* 作用:用于限制变量的作用范围*/
{
System.out.println("我是一个局部代码块~");
}
}
}
结论:执行顺序:静态代码块 --> 构造代码块 --> 构造方法 --> 局部代码块
3 final
3.1 概念
- 是java提供的一个关键字
- final是最终的意思
- final可以修饰类,方法,字段(属性)
初衷:java出现继承后,子类可以更改父类的功能,当父类功能不许子类改变时,可以利用final关键字修饰父类。
3.2 特点
- 被final修饰的类,不能被继承
- 被final修饰的方法,不能被重写
- 被final修饰的字段是个常量,值不能被修改
- 常量的定义形式:final 数据类型 常量名 = 值
练习:final入门案例
package cn.tedu.oop;
/*本类用于测试final关键字*/
public class TestFinal {
}
//1.定义父类
/*1.final可以用来修饰类,被final修饰的类是最终类,不可以被继承
* 可以把被final修饰的类看成树结构中的叶子节点*/
//3.测试类被final修饰
//final class Father2{
class Father2{
//4.定义父类的普通方法
/*2.final可以用来修饰方法,被final修饰的方法是这个方法的最终实现,不可以被重写*/
//6.测试方法被final修饰
//public final void work(){
public void work(){
System.out.println("在工厂里上班~");
}
}
//2.定义子类
class Son2 extends Father2{
final int C = 66;
//5.重写父类的方法
@Override//这个注解用来标记这是一个重写的方法
public void work(){
/*3.被final修饰的是常量,常量的值不可以被修改
* 注意:不管是成员位置还是局部位置,常量定义的时候必须赋值
* 注意:常量的名称必须是全大写,单词与单词之间使用_分割*/
final int B = 100;
//B = 200;//报错:常量的值不可以被修改
System.out.println("在互联网大厂上班~");
System.out.println(Integer.MAX_VALUE);
}
}
17 多态
1. 概念
多态是面向对象程序设计(OOP)的一个重要特征,指同一个实体同时具有多种形式,即同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。
可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
比如,你的女盆友让你买点水果回来,不管买回来的是苹果还是西瓜,只要是水果就行,这个就是生活中多态的体现
再比如,小猫、小狗、小猪我们可以把他们都归纳成小动物,每种小动物都需要吃东西,所以我们可以统一设置他们都必须吃,但是每种小动物的习性不一样,那这个就可以设置成小动物自己特有的功能,多态对象只能调用父类中定义子类中重写的功能,并不能调用子类的特有功能,这样就实现了代码的统一
2 . 特点
- 多态的前提1:是继承
- 多态的前提2:要有方法的重写
- 父类引用指向子类对象,如:Animal a = new Cat();
- 多态中,编译看左边,运行看右边
练习:多态入门案例
package cn.tedu.oop2;
/*本类用作多态的入门案例*/
public class TestDemo {
public static void main(String[] args) {
//6.创建“纯纯的”对象用于测试
Animal a = new Animal();
Cat c = new Cat();
Dog d = new Dog();
a.eat();//小动物Animal吃啥都行~调用的是父类自己的功能
c.eat();//小猫爱吃小鱼干~调用的是子类重写后的功能
d.eat();//小狗爱吃肉骨头~调用的是子类重写后的功能
/*2.父类对象不可以使用子类的特有功能*/
//a.jump();//报错,Animal类里并没有这个方法
//a.run();//报错,Animal类里并没有这个方法
c.jump();//小猫Cat跳的老高啦~,子类可以调用自己的功能
d.run();//小狗Dog跑的老快啦~,子类可以调用自己的功能
//7.创建多态对象进行测试
/*3.口诀1:父类引用指向子类对象
* 解释:创建出来的子类对象的地址值,交给父类类型的引用类型变量来保存*/
Animal a2 = new Cat();//Cat类对象的地址值交给父类型变量a2来保存
Animal a3 = new Dog();//Dog类对象的地址值交给父类型变量a3来保存
//8.测试多态对象
/*4.口诀2:编译看左边,运行看右边
* 解释:必须要在父类定义这个方法,才能通过编译,把多态对象看作是父类类型
* 必须要在子类重写这个方法,才能满足多态,实际干活的是子类*/
a2.eat();//小猫爱吃小鱼干~,多态对象使用的是父类的定义,子类的方法体
}
}
/*1.多态的前提:继承+重写*/
//1.创建父类
class Animal{
//3.创建父类的普通方法
public void eat(){
System.out.println("小动物Animal吃啥都行~");
}
}
//2.1创建子类1
class Cat extends Animal{
//4.1添加重写的方法
public void eat(){
System.out.println("小猫爱吃小鱼干~");
}
//5.1添加子类的特有功能
public void jump(){
System.out.println("小猫Cat跳的老高啦~");
}
}
//2.2创建子类2
class Dog extends Animal{
//4.2添加重写的方法
@Override
public void eat(){
System.out.println("小狗爱吃肉骨头~");
}
//5.2添加子类的特有功能
public void run(){
System.out.println("小狗Dog跑的老快啦~");
}
}
4. 多态的好处
- 多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法
- 提高了程序的可扩展性和可维护性
5. 多态的使用
前提:多态对象把自己看做是父类类型
- 成员变量: 使用的是父类的
- 成员方法: 由于存在重写现象,所以使用的是子类的
- 静态成员: 随着类的加载而加载,谁调用就返回谁的
6 静态变量和实例变量的区别
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
7 向上转型和向下转型
在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。
那么在这个过程中就存在着多态的应用。存在着两种转型方式,分别是:向上转型和向下转型。
向上转型:可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
18 异常
1 概述
异常是一些用来封装错误信息的对象
它由异常的类型、提示信息、报错的行号提示三部分组成
2 异常的继承结构
3 异常的处理方式
当程序中遇到了异常,通常有两种处理方式:捕获或者向上抛出
当一个方法抛出异常,调用位置可以不做处理继续向上抛出,也可以捕获处理异常
大家可以结合生活中的例子:如果工作中遇到了问题,我们可以选择自己处理(捕获),或者交给上级处理(抛出)
对于不想现在处理或者处理不了的异常可以选择向上抛出
方式:在方法上设置异常的抛出管道,即:
在可能会会发生异常的方法上添加代码:
throws 异常类型
例如:void method1 throws Exception1,Exception2,Exception3{ }
TIPS:方法上有默认的异常管道:RuntimeException
4 拓展1 catch 和 throws
异常处理只有两种方式: catch 和 throws,所以必须二选一
由于Java语法本身的特点,需要开发者事先考虑异常如何处理,也就是我们常说的:“未雨绸缪”
对于初级开发者来说,我们可能会捕获,但不处理异常
try {
…
} catch(Exception e) {
}
底层异常,应该向前抛到前面处理
经验少时,不知道该在什么位置捕获处理,应该选择 throws
但是大家需要注意,在异常抛出时,有些异常比如运行时异常,可能并不会强制要求抛出此异常,调用时也没有报错显示需要额外处理,这个时候就需要大家平时多积累,掌握良好的编码习惯了,手动添加代码进行预处理,增强程序的健壮性了。
5 拓展2
程序错误分为三种:
编译错误(checked异常);
运行时错误(unchecked异常);
逻辑错误;
- 编译错误是因为程序没有遵循语法规则,编译程序能够自己发现并且提示我们错误的原因和位置,这个也是大家在刚接触编程语言最常遇到的问题。
- 运行时错误是因为程序在执行时,运行环境发现了不能执行的操作。
- 逻辑错误是因为程序没有按照预期的逻辑顺序执行。异常也就是指程序运行时发生错误,而异常处理就是对这些错误进行处理和控制。
6 拓展3
throws 与 throw 的区别
throws
用在方法声明处,其后跟着的是异常类的名字
表示此方法会抛出异常,需要由本方法的调用者来处理这些异常
但是注意:这只是一种可能性,异常不一定会发生
throw
用在方法的内部,其后跟着的是异常对象的名字
表示此处抛出异常,由方法体内的语句处理
注意:执行throw一定抛出了某种异常
19 抽象类
1 概念
Java中可以定义被abstract关键字修饰的方法,这种方法只有声明,没有方法体,叫做抽象方法.
Java中可以定义被abstract关键字修饰的类,被abstract关键字修饰的类叫做抽象类
- 如果一个类含有抽象方法,那么它一定是抽象类
- 抽象类中的方法实现交给子类来完成
2 抽象方法的格式
3 特点
- abstract 可以修饰方法或者类
- 被abstarct修饰的类叫做抽象类,被abstract修饰的方法叫做抽象方法
- 抽象类中可以没有抽象方法
- 如果类中有抽象方法,那么该类必须定义为一个抽象类
- 子类继承了抽象类以后,要么还是一个抽象类,要么就把父类的所有抽象方法都重写
- 多用于多态中
- 抽象类不可以被实例化
拓展
总结:abstract注意事项
抽象方法要求子类继承后必须重写。
那么,abstract关键字不可以和哪些关键字一起使用呢?以下关键字,在抽象类中。用是可以用的,只是没有意义了。
1.private:被私有化后,子类无法重写,与abstract相违背。
2.static:静态优先于对象存在,存在加载顺序问题。
3.final:被final修饰后,无法重写,与abstract相违背。
20 接口
1 接口的概念
与之前学习过的抽象类一样,接口( Interface )在Java中也是一种抽象类型,接口中的内容是抽象形成的需要实现的功能,接口更像是一种规则和一套标准.
2 接口格式
3 接口的特点:
- 通过interface关键字来定义接口
- 通过implements让子类来实现接口
- 接口中的方法全部都是抽象方法(JAVA8)
- 可以把接口理解成一个特殊的抽象类(但接口不是类!!!)
- 类描述的是一类事物的属性和方法,接口则是包含实现类要实现的方法
- 接口突破了java单继承的局限性
- 接口和类之间可以多实现,接口与接口之间可以多继承
- 接口是对外暴露的规则,是一套开发规范
- 接口提高了程序的功能拓展,降低了耦合性
练习: 创建接口实现类
package cn.tedu.inter;
/*本类作为Inter接口的实现类*/
/*1.实现类如果想要实现接口定义的功能,需要与接口建立实现关系
* 通过关键字implements来建立实现类 实现 接口的关系*/
/*2.1 方案一:如果实现类与接口建立实现关系以后
可以选择不实现接口中的抽象方法,把自己变成一个抽象类*/
//abstract public class InterImpl implements Inter{//方案一
/*2.2方法二:如果实现类与接口建立实现关系以后
* 还可以选择实现接口中的所有抽象方法,把自己变成一个普通子类*/
public class InterImpl implements Inter{
@Override
public void eat() {
System.out.println("吃火锅");
}
@Override
public void play() {
System.out.println("玩代码");
}
}
8 总结
1. 类与类的关系
继承关系,只支持单继承
比如,A是子类 B是父类,A具备B所有的功能(除了父类的私有资源和构造方法)
子类如果要修改原有功能,需要重写(方法签名与父类一致 + 权限修饰符>=父类修饰符)
2. 类和接口的关系
实现关系.可以单实现,也可以多实现
class A implements B,C{}
其中A是实现类,B和C是接口,A拥有BC接口的所有功能,只是需要进行方法的重写,否则A就是抽象类
3. 接口与接口的关系
是继承关系,可以单继承,也可以多继承
interface A extends B,C{}
其中ABC都是接口,A是子接口,具有BC接口的所有功能(抽象方法)
class X implements A{}
X实现类需要重写ABC接口的所有方法,否则就是抽象类
class A extends B implements C,D{}
其中A是实现类,也是B的子类,同时拥有CD接口的所有功能
这时A需要重写CD接口里的所有抽象方法
4.接口与抽象类的区别
- 接口是一种用interface定义的类型
抽象类是一种用class定义的类型 - 接口中的方法都是抽象方法,还有默认方法与静态方法
抽象类中的方法不做限制 - 接口中的都是静态常量
抽象类中可以写普通的成员变量 - 接口没有构造方法,不可实例化
抽象类有构造方法,但是也不可以实例化 - 接口是先天设计的结果,抽象是后天重构的结果
- 接口可以多继承
抽象类只能单继承
Boolean equals 方法(要比较的字符串) 完全一样结果才是true,否则为false;
Boolean equalslgnoreCase 方法(要比较的字符串)忽略大小写
21 内部类概述
如果一个类存在的意义就是为指定的另一个类,可以把这个类放入另一个类的内部。
就是把类定义在类的内部的情况就可以形成内部类的形式。
A类中又定义了B类,B类就是内部类,B类可以当做A类的一个成员看待:
2 特点
1) 内部类可以直接访问外部类中的成员,包括私有成员
练习 : 内部类入门案例
package cn.tedu.innerclass;
/*本类用作测试内部类的入门案例*/
public class TestInner1 {
public static void main(String[] args) {
//3.创建内部类对象,使用内部类的资源
/*外部类名.内部类名 对象名 = 外部类对象.内部类对象*/
Outer.Inner oi = new Outer().new Inner();
oi.delete();
System.out.println(oi.sum);
//4.调用外部类的方法--这样是创建了一个外部类的匿名对象,只使用一次
new Outer().find();
}
}
//1.创建外部类 Outer
class Outer{
//1.1创建外部类的成员变量
String name;
private int age;
//1.2创建外部类的成员方法
public void find(){
System.out.println("Outer...find()");
//6.测试外部类如何使用内部类的资源
//System.out.println(sum);--不能直接使用内部类的属性
//delete();--不能直接调用内部类的方法
/*外部类如果想要使用内部类的资源,必须先创建内部类对象
* 通过内部类对象来调用内部类的资源*/
Inner in = new Inner();
System.out.println(in.sum);
in.delete();
}
//2.创建内部类Inner--类的特殊成员
/*根据内部类位置的不同,分为:成员内部类(类里方法外)、局部内部类(方法里)*/
class Inner{
//2.1定义内部类的成员变量
int sum = 10;
//2.2定义内部类的成员方法
public void delete(){
System.out.println("Inner...delete()");
//5.测试内部类是否可以使用外部类的资源
/*结论:内部类可以直接使用外部类的资源,私有成员也可以!*/
System.out.println(name);
System.out.println(age);
/*注意:此处测试完毕需要注释掉,否则来回调用
* 会抛出异常StackOverFlowException栈溢出异常*/
//find();
}
}
}
练习 : 被private修饰
package cn.tedu.innerclass;
/**本类用来测试成员内部类被private修饰*/
public class TestInner2 {
public static void main(String[] args) {
/**怎么使用内部类Inner2的资源?*/
//4.创建内部类Inner2对象进行访问
//Outer2.Inner2 oi = new Outer2().new Inner2();
//oi.eat();
/**如果Inner2被private修饰,无法直接创建对象该怎么办?*/
//7.创建外部类对象,间接访问私有内部类资源
new Outer2().getInner2Eat();
}
}
//1.创建外部类Outer2
class Outer2{
//6.提供外部类公共的方法,在方法内部创建Inner2内部类对象,调用内部类方法
public void getInner2Eat() {
Inner2 in = new Inner2();//外部类可以访问内部类的私有成员
in.eat();
}
//2.1创建成员内部类Inner2
/**成员内部类的位置:类里方法外*/
//5.成员内部类,被private修饰私有化,无法被外界访问
private class Inner2{
//3.创建内部类的普通成员方法
public void eat() {
System.out.println("我是Inner2的eat()");
}
}
}
总结:
成员内部类被Private修饰以后,无法被外界直接创建创建对象使用
练习 : 被static修饰
package cn.tedu.innerclass;
/**本类用来测试成员内部类被static修饰*/
public class TestInner3 {
public static void main(String[] args) {
/**如何访问内部类的show()?*/
//4.创建内部类对象访问show()
//方式一:按照之前的方式,创建内部类对象调用show()
//Outer3.Inner3 oi = new Outer3().new Inner3();
//oi.show();
//方式二:创建匿名内部类对象访问show()
//new Outer3().new Inner3().show();
/**现象:当内部类被static修饰以后,new Outer3()报错*/
//6.用static修饰内部类以后,上面的创建语句报错,注释掉
//通过外部类的类名创建内部类对象
Outer3.Inner3 oi = new Outer3.Inner3();
oi.show();
//7.匿名的内部类对象调用show()
new Outer3.Inner3().show();
//9.访问静态内部类中的静态资源--链式加载
Outer3.Inner3.show2();
}
}
//1.创建外部类Outer3
class Outer3{
//2.创建成员内部类Inner3
//5.内部类被static修饰—并不常用!浪费内存!
static class Inner3{
//3.定义成员内部类中普通的成员方法
public void show() {
System.out.println("我是Inner3类的show()");
}
//8.定义成员内部类的静态成员方法
static public void show2() {
System.out.println("我是Inner3的show2()");
}
}
}
总结:
访问静态类中的静态资源可以通过”. . . ”链式加载的方式访问
局部内部类
package cn.tedu.innerclass;
/**本类用来测试局部内部类*/
public class TestInner4 {
public static void main(String[] args) {
/**如何使用内部类的资源呢?
* 注意:直接调用外部类的show()是无法触发内部类功能的
* 需要再外部类中创建内部类对象并且进行调用,才能触发内部类的功能
* */
//5.创建外部类对象调用show()
//7.当在外部类show()中创建局部内部类对象并且进行功能调用后,内部类的功能才能被调用
new Outer4().show();
}
}
//1.创建外部类Outer4
class Outer4{
//2.创建外部类的成员方法
public void show() {
//3.创建局部内部类Inner4—不太常用!!!
/**位置:局部内部类的位置在方法里*/
class Inner4{
//4.创建局部内部类的普通属性与方法
String name;
int age;
public void eat() {
System.out.println("我是Inner4的eat()");
}
}
/**如何使用局部内部类的资源?*/
//6.在show()里创建内部类对象
Inner4 in = new Inner4();
in.eat();
System.out.println(in.name);
System.out.println(in.age);
}
}
匿名内部类
package cn.tedu.innerclass;
/*本类用于测试匿名内部类
* 匿名内部类没有名字,通常与匿名对象结合在一起使用*/
public class TestInner5 {
public static void main(String[] args) {
//传统方式:创建接口的实现类+实现类实现接口中的抽象方法+创建实现类对象+通过对象调用方法
//3.创建接口一对应的匿名对象与匿名内部类,并调用实现了的方法save()
new Inter1(){
@Override
public void save() {
System.out.println("save()...");
}
@Override
public void get() { }
}.save();
//5.创建抽象类对应的匿名对象与匿名内部类
new Inter2(){
@Override
public void drink() {
System.out.println("一人饮酒醉");
}
}.drink();
//7.调用普通类的功能怎么调用?创建匿名对象直接调用
new Inter3().powerUp();
new Inter3().powerUp();//new了2次,所以是两个匿名对象
/*如果想要多次使用实现后的功能,还是要创建普通的对象
* 匿名对象只能使用一次,一次只能调用一个功能
* 匿名内部类其实就充当了实现类的角色,去实现未实现的抽象方法,只是没有名字而已*/
Inter3 in = new Inter3();
in.study();
in.study();
in.study();
in.study();
in.study();
in.study();
}
}
//1.创建接口
interface Inter1{
//2.定义接口中的抽象方法
void save();
void get();
}
//4.创建抽象类
abstract class Inter2{
public void play(){
System.out.println("Inter2...play()");
}
abstract public void drink();
}
//6.创建普通类
class Inter3{
public void study(){
System.out.println("什么都阻挡不了我想学习赚钱的决心");
}
public void powerUp(){
System.out.println("我们会越来越强的!");
}
}
总结:
匿名内部类属于局部内部类,而且是没有名字的局部内部类,通常和匿名对象一起使用