Day1
Java语言平台的版本
-Java SE(标准版) 为开发普通桌面和商务程序提供解决方案 是Java ME 和 Java EE 的基础,可以完成一些桌面应用程序的开发
-Java ME (小型版) 为开发电子消费产品和嵌入式设备提供解决方案
-Java EE(企业版) 为开发企业环境下的应用程序提供一套解决方案,该技术主要包括Select,jsp,主要针对Web应用开发
Java语言的特点
简单性,解释性,面向对象,高性能,分布式处理,多线程,健壮性,动态,结构性,安全性,开源,跨平台(JVM相当于翻译,Java可以跨平台,JVM不可以跨平台,针对每个操作系统都有对应的JVM)
第一个程序HelloWorld
class HelloWord{
public static void main(String[] args) {
System.out.println("hello,world");
}
}
写程序的步骤
/*
需求: 在控制台上输出Hello,World
分析:
1.要写一个Java程序,必须先定义一个类
2.程序要想运行,必须有main函数
3.输出一个语句必须用到输出语句
实现:
1.定义类用到class,后边跟类名
2.main函数的格式是固定的
public static void main(String[] args){
表达式或语句
}
3.输出语句的格式是固定的
System.out.println("hello,world"); "hello,world"内容可变
*/
//这是我的第一个程序,输出hello,world
class HelloWord{
//定义main方法,main是程序的入口,被JVM自动调用
public static void main(String[] args){
//输出语句
System.out.println("hello,world");
}
}
Day2
原码反码和补码
原码 反码 补码
正数 二进制 与原码相同 与原码相同
负数 二进制 将原码取反 将反码末位+1
负数将反码转换成原码需要先减一在取反
数据类型
数据类型分为基本数据类型和引用数据类型(类,接口,数组)
基本数据类型(4类8种)
占用字节 范围
整数
byte 1 -128到127
shor 2 -2的15次方到2的15次方-1
int 4 -2的31次方到2的31次方-1
long 8 -2的63次方到2的63次方-1
浮点数
float 4 -3.043E38到3.403E38
double 8 -1.798E308到1.798E308
字符
cha r 2
布尔
boolean 1
在定义Long或者Float类型的数据时,要在数据后边加L或F
整数默认的类型为Int,浮点数默认的为double
byte和short在定义的时候默认接收的是一个整数,如果不在自己的范围内就报错
命名规则
常见的命名规则:见名知意
举例:我要定义一个学生类
class Student {}
class S{}
包:其实就是文件夹,用于把相同的类名进行区分
全部小写
单级: zhangsan
多级:cn.baidu
类或者接口:
一个单词:单词的首字母必须大写
举例:Student,Dog
多个单词:每个单词的首字母必须大写
举例:HelloWorld,StudentName
方法或者变量:
一个单词:单词的首字母小写
举例:main,age
多个单词:从第二个单词开始,每个单词的首字母大写
举例:studentAge,showAllNames()
常量:
一个单词:全部大写
举例:PI
多个单词:每个字母都大写,用_隔开
举例:STUDENT_MAX_AGE
默认数据类型转换
是从小的范围到大的范围进行转换
byte,short,char→int→long→folat→double
注意:byte,short,long不可以相互转换,在运算时默认转换成int进行运算
运算过程种有范围大的数据类型,结果一定是范围大的数据类型
例:3(int)+3.55(double)结果是6.55(double),赋值时一定要注意
强制数据类型转换
格式:目标数据类型 变量 =(目标数据类型)(被转换的数据);
例: int a = (int)(3+3.2); 结果为6
注意:强制类型转换会损失精度,3+3.2应该等于6.2,但int只能取整数部分
//下列两个语句那个会编译报错,为什么
byte b1 = 3;
byte b2 = 4;
byte b;
b = b1 + b2;//会报错,在运算时,byte,short,char会转换成int类型进行运算,Int占4位,赋值给byte类型会报错
b = 3+4;//不会报错,先将3+4的运算结果算出来,再看运算结果是否在byte 数据范围内,若在,则不报错
//将130赋值给byteb是否有问题?如果想赋值应该怎么写?结果是多少?
byte b = 130;//会报错,因为byte的取值范围为-127到128
byte b = (byte)(130);//可以进行强制类型转换
//结果为-126
/*
分析过程
要想知道为什么结果为-126,就需要知道数据在计算机是如何进行运算的
计算机中的数据是通过补码进行运算的
获取130的二进制,130为整数,默认占4个字节
00000000 00000000 0000000 10000010
这是130的原码,正数的原码反码补码都相同,所以这也是130的补码
byte b 为字节,默认占1位字节,要对130的补码进行截取
得到 10000010 这是补码,且第一位为0,所以为负数,将负数的补码转换成原码
得到11111110 即-126
*/
输出的几种形式
System.out.println("hello"+'a'+1);//结果为helloa1
System.out.println('a'+1+"hello");//结果为98hello
//因为字符串数据和其他数据做+,结果依旧是字符串类型
//这里的+不是加法运算,而是作为连接符
System.out.println("5+5="+5+5);//结果为5+5=55,"5+5="为字符串,所以+为连接符
System.out.println(5+5+"=5+5");//结果为10=5+5,从左到右进行运算
记住'a'的Ascll码为97,'A'的Ascll码为65,'0'的Ascll码为48
算数运算符
++,--运算符
单独使用时:
放在变量前边和后边的用法是一样的
参入运算时:
放在变量的前边时,先进行自增或自减,在参入运算
放在变量的后边时,先参入运算,在进行自增或自减
作用:对变量进行自增1或者自减1
赋值运算符
=,+=,-=,*=,/=,%=
=是基本的赋值运算符,其他的是拓展的赋值运算符
+=就是将左边和右边相加然后赋值给左边
例:a += 3;就是将a+3的值赋值给a
//拓展的赋值运算符隐含了强制类型转
short s ;
s = s + 1;//会报错,因为short在运算时会转换成int类型,所以将int赋值给short是错误的
s+=1;//不会报错,拓展赋值运算符相当于 s = (s的数据类型)(s+1);进行强制类型转换
关系运算符
不管进行什么操作,结果一定是布尔类型
逻辑运算符
逻辑运算符用于连接布尔类型的表达式
&与 一假即假
|或 一真即真
^异或 相同为假,不同为真
&和&&的区别:
&的左边为假时,则不对右边进行运算,直接忽略
&&不管左边是否为假,右边都要进行运算
|与||同上
位运算符
直接对二进制进行运算,对数的补码进行操作
&与位运算:有0则0;|或位运算:有1则1;^位异或运算:相同为0,不同为1;
一个数与两个相同的数进行异或,结果不变
例:a ^ b ^ b; 结果为a
<<相当于把左边的数据乘以2的移动次幂,>>相当于把左边的数据除以2的移动次幂
操作时注意是对补码进行运算,换算成二进制是原码,注意负数;
//交换两个整数的位置
int a = 10,b = 20;
//第一种方法,利用空变量进行交换(开发)
int c;
c = a;
a = b;
b = c;
//第二种方法,利用位异或实现(面试)
a = a ^ b;//不计算,直接带到下边
b = a ^ b;//b = a ^ b ^ b; 相当于 b = a;
a = a ^ b;// b = a ^ b ^ a;因为上边 b = a;
//第三种方法,利用变量加法
a = a+ b;//不计算,直接带入下边
b = a - b;// b = a + b - b;得 b = a
a = a - b;// a = a + b - a 得 a = b
//第四种方法,一句话搞定
b = (a+b) - (a = b);//相当于把b赋给a,得到 b = (a+b) - b
优先级
口诀单目乘除为关系,逻辑三目后赋值。
Day3
三目运算符
格式:(关系表达式)?表达式1:表达式2;
如果表达式为真,则取表达式1的值,如果为假,则取表达式2的值
//求两个数中的最大值
int a = 3,b = 5;
int max = (a>b)?a:b;//如果a大于b,则把a的值给max,如果a不大于b,则把b的值给max
键盘录入数据
第一步导包:在所有的class定义之上
import java.util.Scanner;
第二步:创建对象:
Scanner sc = new Scanner(System.in);
第三步:接收数据:
int a = sc.nextInt();
nextInt只能获取Int类型的数,可以有nextFloat,nextDouble等
import java.util.Scanner;//导包
class Get Keyboard{
public static void main(String[] agrs){
Scanner sc = new Scanner(System.in);//创建对象sc
int a;
a = sc.nextInt();//用a接收键盘输入的数据
System.out.println("从键盘获取的是"+a);
}
}
流程控制语句
-顺序结构
-选择结构
-循环结构
顺序结构
最基本的流程控制,就是按照从上往下执行,先写的先执行
选择结构
也称为分支结构,选择结构有特定的语法规则,代码要执行具体的逻辑运算进行判断,逻辑运算的结果有两个,所以产生选择,按照不同的选择执行不同的代码。
java提供了两种选择结构语句
-if语句
-switch语句
if语句
if语句有三种格式
/*
if语句第一种格式:
if(关系表达式) {
语句体
}
执行流程
首先判断关系表达式看其结果是true还是false
如果是true就执行语句体
如果是false就不执行语句体
*/
int a = 20;
int b = 10;
if(a>b){ //先判断表达式a>b的结果是真还是假
System.out.println("a大于b");//如果为真则执行输出语句,为假则不执行
}
/*
if语句第二种格式:
if(关系表达式) {
语句体1;
}else {
语句体2;
}
执行流程
首先判断关系表达式看其结果是true还是false
如果是true就执行语句体1
如果是false就执行语句体2
*/
int a = 20;
int b = 10;
if(a>b){ //先判断表达式a>b的结果是真还是假
System.out.println("a大于b");//如果为真则执行if语句体,为假则输出else语句体
}else {
System.out.println("b大于a");
}
/*
if语句第三种格式:
if(关系表达式1) {
语句体1;
}else if (关系表达式2) {
语句体2;
}
…
else {
语句体n+1;
}
首先判断关系表达式1看其结果是true还是false
如果是true就执行语句体1
如果是false就继续判断关系表达式2看其结果是true还是false
如果是true就执行语句体2
如果是false就继续判断关系表达式…看其结果是true还是false
…
如果没有任何关系表达式为true,就执行语句体n+1
int a = 20;
int b = 10;
if(a>b){ //先判断表达式a>b的结果是真还是假
System.out.println("a大于b");//为真则执行if语句体
}else if(b>a) {//为假则判断else if的表达式是真还是假
System.out.println("b大于a");
}else {
System.out.println("a等于b");
}
*/
if语句的使用场景
针对结果是boolean类型的判断
针对一个范围的判断
针对几个常量值的判断
switch语句
/*
switch语句格式:
switch(表达式) {
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
…
default:
语句体n+1;
break;
}
*/
switch语句使用场景
针对几个常量值的判断
循环结构
循环语句的组成
初始化语句:
一条或者多条语句,这些语句完成一些初始化操作
判断条件语句:
这是一个boolean 表达式,这个表达式能决定是否执行循环体
循环体语句:
这个部分是循环体语句,也就是我们要多次做的事情
控制条件语句:
这个部分在一次循环体结束后,下一次循环判断条件执行前执行。通过用于控制循环条件中的变量,使得循环在合适的时候结束
for循环语句格式
格式:
for(初始化语句;判断条件语句;控制条件语句) {
循环体语句;
}
执行流程
1.执行初始化语句
2.执行判断条件语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
3.执行循环体语句
4.执行控制条件语句
5.回到2继续
//用for循环求1-10的和
int num = 0,i;
for(i = 0;i < 10;i++){
num = num +i;
}
System.out.println("1-10的和为"+num);
//求100-1000之间有哪些水仙花数
int i,x,y,z; //水鲜花数是一种三位数,其各个数之立方和等于该数
for(i = 100;i < 1000;i++){
x = i/100; //125整除100,得1
y = i/10%10; //125整除10,得12然后在取余10得2,即125的十位
z = i%10; //125取余10得5
if(i == x*x*x + y*y*y* +z*z*z){
System.out.println("水仙花数"+i);
}
}
while循环语句
格式:
基本格式
while(判断条件语句) {
循环体语句;
}
扩展格式
初始化语句;
while(判断条件语句) {
循环体语句;
控制条件语句;
}
//利用while循环求一张0.01M的纸折叠多少次可以超过珠穆朗玛峰8848M
double i = 0.01;
int j=0;//表示折叠的次数
while (i <= 8848){ //只要i小于8848就一直执行,直到i大于8848结束
j++;
i = i*2;
}
System.out.println("折叠了"+j+"次");
do while循环
格式:
基本格式
do {
循环体语句;
}while((判断条件语句);
扩展格式
初始化语句;
do {
循环体语句;
控制条件语句;
} while((判断条件语句);
do while 循环最少会执行一次循环体,while,for则是必须条件为真才会执行
循环练习
/*
输出 *
**
***
****
*****
分析:输出5行*,依次增加数量
*/
for(int i = 0;i < 5;i++){ //控制外层循环5次
for(int j = 0;j < i+1;j++){ //控制*输出的个数每次加1
System.out.print("*"); //print 输出完不进行换行
}
System.out.println(); //println输出完进行换行,可以输出空进行换行
}
//输出九九乘法表
for (int i = 1; i < 10; i++) {
for (int j = 1; j < i+1; j++) {
System.out.print(i+"*"+j+"="+i*j+"\t");
}
System.out.println(" ");
}
跳转控制语句:break,continue,return
break:在switch结构和循环中使用,作用是跳出并结束本轮循环
for(int i = 0;i < 5;i++){
if(i == 2){
break;
}
System.out.print("你好"); //结果只输出两个你好,因为在i =2也就是第三次循环的时候,符合if的条件跳出
}
break跳出多层循环的用法
要想跳出多层循环,就必须带标签的跳出
标签的格式: 标签名:循环语句
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
System.out.print("*"); //输出一个四行四列的星号
if(j == 2){
break; //加上break,输出四行三列的星号,因为if语句只是在j等于2的时候结束j的循环
}
}
System.out.println(); //换行
}
//要想退出多层循环就要用标签
out:
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
System.out.println("*");
if(j == 2){
break out; //out:标签的作用就是break直接跳到out:处,且不在执行循环
}
}
System.out.println(); //换行
}
continue:在循环中使用,作用是跳出本次循环,但继续执行下一次循环
for(int i = 1;i < 5;i++){
if(i == 2){
continue; //输出结果为1,3,4,因为在i等于2的时候,符合if语句,所以跳出本次循环,但不结束循环
}
System.out.println(i);
}
continue也可以跳出多层循环,参考break;
return:不是为了跳转出循环体,更常用的功能是结束一个方法,也就是退出一个方法,跳转到上层调用的方法
Day4
方法
完成特定功能的代码块,其他语言称为函数
格式:
修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2...) {
方法体语句;
return 返回值;
}
public static int sum(int a,int b){
int sum = a + b;
return sum;
}
详细解释:
修饰符:目前就用 public static
返回值类型:就是功能结果的数据类型
方法名:符合命名规则即可。方便我们的调用
参数:
实际参数:就是实际参与运算的
形式参数;就是方法定义上的,用于接收实际参数的
参数类型:就是参数的数据类型
参数名:就是变量名
方法体语句:就是完成功能的代码
return:结束方法的。
返回值:就是功能的结果,由return带给调用者
要想写好一个方法,就必须明确两个东西:
-返回值类型
结果的数据类型
-参数列表
你要传递几个参数,以及每个参数的数据类型
方法调用格式(有返回值的):
-单独调用:没意义
-输出调用:写在输出语句中
-赋值调用:调用后赋值给一个变量,方便后期使用
无返回值类型的只能单独调用
方法调用图解
方法的注意事项:
-方法不调用不执行
-方法与方法是平级关系,不能嵌套定义
-方法定义的时候参数之间用逗号隔开
-方法调用的时候不用在传递数据类型
-如果方法有明确的返回值,一定要有return带回一个值
方法重载
在同一个类中,方法名相同,参数列表不同,与返回值类型无关
参数列表不同:
-参数个数不同
-参数类型不同
方法重载特点
-与返回值类型无关,只看方法名和参数列表
-在调用时,虚拟机通过参数列表的不同来区分同名方法
public static void main(String[] args) {
//方法重载,比较int和float数据是否相同
int a = 3;
int b = 4;
int c = 5;
boolean flag = compare(a, b); //根据给的参数的类型去匹配compare方法的类型
System.out.println(flag); //输出int false
float f = 2.2f;
float f1 = 2.2f;
boolean flag1 = compare(f,f1);
System.out.println(flag1); //输出float true
}
public static boolean compare(int a,int b,int c){ //比较int
System.out.println("int");
return (a ==b);
}
public static boolean compare(float a,float b) { //比较float
System.out.println("float");
return (a == b);
}
数组
数组是存储同一种数据类型多个元素的集合,也可以看成是一个容器
数组既可以存储基本数据类型,也可以存储引用数据类型
数组定义:
-格式1:数据类型[] 数组名;
int [] arr;
-格式2:数据类型 数组名[];
int arr [];
数组的初始化:
-动态初始化:初始化时只指定数组长度,由系统为数组分配初始值
格式:数据类型[] 数组名 = new 数据类型[数组长度];
数组长度就是数组中元素的个数
int [] arr = new int [5]; //定义了一个int类型的数组,这个数组可以存放3个int类型的值
-静态初始化:初始化时指定每个数组元素的初始值,由系统决定数组长度
格式:数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…};
int [] arr = new int []{1,2,3,4,5};
//可以简写为:
int [] arr = {1,2,3,4,5};
数组的长度可以用数组名.length表示
int [] arr = {1,2,3,4,5};
arr.length 就等于5
java的内存分配
Java 程序在运行时,需要在内存中的分配空间。为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式
-栈 存储局部变量
-堆 存储new出来的东西
-方法区 (面向对象)
-本地方法区 (和系统相关)
-寄存器 (给CPU使用)
数组遍历及输出
//数组的遍历及输出
int [] arr = {1,2,5,6,8,7,1,5};
for (int i = 0; i < arr.length; i++) {
System.out.println("第"+(i+1)+"个元素为"+arr[i]);
//求一个数在数组中第一次出现的位置
int [] arr = {1,2,5,6,8,7,1,5};
System.out.println("请输入一个数");
Scanner sc = new Scanner(System.in); //在类上导包
int num = sc.nextInt(); //获取键盘数据
boolean flag = true; //判断
for (int i = 0; i < arr.length; i++) {
if (num == arr[i]) {
System.out.println("该数据首次出现在第" + (i + 1) + "个位置");
flag = false; //如果输入的数据在数组中,则把判断位变为flase
break;
}
}
if (flag){ //对判断位进行判断,若为真,则说明if语句未执行
System.out.println("该数据没有在数组中");
{
冒泡排序
//从小到大排列数组
int [] arr = {1,2,5,6,8,7,9,15};
int tmp = 0; //中间变量
for (int i = 0; i < arr.length-1; i++) { //外层循环控制比较次数,8个数需要7轮比较完
for (int j = 0; j < arr.length-1; j++) { //内层循环控制每次比较的次数,8个数需要7次比较
if (arr[i] > arr[i+1]){ //如果前边的数比后边的数大,就换位置
tmp = arr[i]; //中间变量,交换位置
arr[i] = arr[i+1];
arr[i+1] = tmp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
数组常见错误
数组索引越界 ArrayIndexOutOfBoundsException
访问到了数组中的不存在的索引时发生
空指针异常 NullPointerException
数组引用没有指向实体,却在操作实体中的元素时
Day5
二维数组
格式1:
数据类型[][] 数组名 = new 数据类型[m][n];
m:表示这个二维数组有多少个一维数组
n:表示每一个一维数组的元素有多少个
注意:
以下格式也可以表示二维数组:
-数据类型 数组名[][] = new 数据类型[m][n];
-数据类型[] 数组名[] = new 数据类型[m][n];
class Array2 {
public static void main(String[] args) {
//定义一个二维数组
int[][] arr = new int[3][2];
//定义了一个二维数组arr
//这个二维数组有3个一维数组的元素
//每一个一维数组有2个元素
//输出二维数组名称
System.out.println(arr); //地址值 [[I@175078b
//输出二维数组的第一个元素一维数组的名称
System.out.println(arr[0]); //地址值 [I@42552c
System.out.println(arr[1]); //地址值 [I@e5bbd6
System.out.println(arr[2]); //地址值 [I@8ee016
//输出二维数组的元素
System.out.println(arr[0][0]); //0
System.out.println(arr[0][1]); //0
}
}
格式2:
数据类型[][] 数组名 = new 数据类型[m][];
m:表示这个二维数组有多少个一维数组
列数没有给出,可以动态的给,这一次是一个变化的列数
格式3:
基本格式:
数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}};
简化版格式:
数据类型[][] 数组名 = {{元素1,元素2...},{元素1,元素2...},{元素1,元素2...}};
举例:
int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
int[][] arr = {{1,2,3},{4,5},{6}};
二维数组的遍历
public class Arr2Print {
public static void main(String[] args) {
//定义一个二维数组进行遍历
int [] [] arr = {{1,2,3},{4,5},{6}};
//利用每个数组的长度进行遍历
for (int i = 0; i < arr[0].length; i++) {
System.out.print(arr[0][i]+" ");
}
System.out.println();
for (int i = 0; i < arr[1].length; i++) {
System.out.print(arr[1][i]+" ");
}
System.out.println();
for (int i = 0; i < arr[2].length; i++) {
System.out.print(arr[2][i]+" ");
}
System.out.println();
//可以用嵌套
for (int i = 0; i < arr.length; i++) { //arr.length代表二维数组的长度,也就是一维数组的个数
for (int j = 0; j < arr[i].length; j++) { //arr[i].length代表每个一维数组的长度,i从0~2
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
}
打印杨辉三角
public class YangHui {
/**
需求:需求:打印杨辉三角形(行数可以键盘录入)
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
分析:杨辉三角的第一列和最后一列都是1
从第三行开始,每一个数据都是上一列的前一个数据和本列之和
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入行数");
int m = sc.nextInt();
int [][] arr= new int [m][m];
for (int i = 0; i < arr.length; i++) { //使第一列和最后一列都为1
arr[i][0] = 1;
arr[i][i] = 1;
}
//从第三行开始,每一个数据都是上一列的前一个数据和本列之和
for (int i = 2; i < arr.length; i++) { //从第三行开始,所以i= 2
//因为第一列已经赋值了1,所以y从1开始
//因为最后一列赋值了1,所以j
将一个整数的每一位写入到一个数组中
Scanner sc = new Scanner(System.in);
int num = sc.nextInt(); //从键盘获取一个数据
int index = 0; //因为不知道获取了几位数,所以定义一个索引
while (num > 0){ //假设num12345,num = 1234,num = 123,num = 12,num = 1,num = 0,不符合循环条件
arr[index] = num%10; //arr[0] = 5,arr[1] = 4,arr[2] = 3,arr[3] =2,arr[4] = 1
num/=10;//num = 1234,num = 123,num = 12,num = 1,num = 0
index++;//index = 1,index = 2,index = 3,index = 4,index =5,index为索引表示数组长度为5
}
//打印
for (int i = 0; i < index; i++) { //index为索引,及数组长度
System.out.print(arr[i]+" ");
//打印出5 4 3 2 1,但是数据是逆序存入数组的,可以在定义一个数组对arr进行逆序
public class Text1 {
public static void main(String[] args) {
/*
* 某个公司采用公用电话传递数据信息,数据是小于8位的整数,为了确保安全,
在传递过程中需要加密,加密规则如下:
首先将数据倒序,然后将每位数字都加上5,再用和除以10的余数代替该数字,
最后将第一位和最后一位数字交换。 请任意给定一个小于8位的整数,
然后,把加密后的结果在控制台打印出来。
* 分析:小于8位的整数:定义int类型变量,从键盘获取,Scanner
* 将数据倒序,就要获取输入每一位的数,存到数组中
* 将每位数字加5,取余10
* 打印在控制台
* */
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个8位数以下的数");
int num = sc.nextInt(); //从键盘获取
//存到数组中,先定义一个数组
int [] arr = new int[8];//8位及以下,所以写8
int index = 0;//不知道输入了几位数,所以自己定义一个索引
//将从键盘获取的数据一位一位存到数组中
while (num > 0){ //假设num12345,num = 1234,num = 123,num = 12,num = 1,num = 0,不符合循环条件
arr[index] = num%10; //arr[0] = 5,arr[1] = 4,arr[2] = 3,arr[3] =2,arr[4] = 1
num/=10;//num = 1234,num = 123,num = 12,num = 1,num = 0
index++;//index = 1,index = 2,index = 3,index = 4,index =5,index为索引表示数组长度为5
}
//while循环中,不仅将数据写入到数组中,并且完成了倒序
//将每位加5,取余10
for (int i = 0; i < index; i++) {
arr[i] += 5;
arr[i] %= 10;
}
//打印
for (int i = 0; i < index; i++) { //index为索引,及数组长度
System.out.print(arr[i]+" ");
}
}
}
Java中参数传递的问题
-基本类型:形式参数的改变对实际参数没有影响,基本数据类型实参给方法形参传递的是数据值
-引用类型:形式参数的改变直接影响实际参数,引用数据类型实参给方法形参传递的是地址值
//看程序写结果
class ArgsDemo {
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("a:"+a+",b:"+b); //a:10,b:20
change(a,b);
System.out.println("a:"+a+",b:"+b); //a:10,b:20
int[] arr = {1,2,3,4,5};
change(arr);
System.out.println(arr[1]); //4
}
public static void change(int a,int b) { //a=10,b=20
System.out.println("a:"+a+",b:"+b); //a:10,b:20
a = b; //a=20
b = a + b; //b=40
System.out.println("a:"+a+",b:"+b); //a:20,b:40
}
public static void change(int[] arr) { //arr={1,2,3,4,5};
for(int x=0; x
Day6
面向对象
面向对象思想概述
面向对象是基于面向过程的编程思想
面向对象思想特点
-是一种更符合我们思想习惯的思想
-可以将复杂的事情简单化
-将我们从执行者变成了指挥者
在用面向对象思想体现的时候,给出一个三句话使用规则,让我们更符合面向对象思想
-首先分析有那些类
-接着分析每个类应该有什么
-最后分析类与类的关系
面向对象开发
就是不断的创建对象,使用对象,指挥对象做事情
面向对象设计
其实就是在管理和维护对象之间的关系
面向对象特征
-封装(encapsulation)
-继承(inheritance)
-多态(polymorphism)
如何表示一个现实世界事物呢:
-属性 就是该事物的描述信息
-行为 就是该事物能够做什么
类:是一组相关的属性和行为的集合
对象:是该类事物的具体体现
现实世界的事物
属性 人的身高,体重等
行为 人可以学习,吃饭等
Java中用class描述事物也是如此
成员变量 就是事物的属性
成员方法 就是事物的行为
定义类其实就是定义类的成员(成员变量和成员方法)
成员变量 和以前定义变量是一样的,只不过位置发生了改变,在类中,方法外
成员方法 和以前定义方法是一样的,只不过把static去掉
定义一个类
如何定义
按照事物到类的过程一步步分析
/*
手机事物:
属性:品牌,价格,颜色...
行为:打电话,发短信,玩游戏...
手机类:
成员变量:品牌,价格,颜色
成员方法:打电话,发短信,玩游戏
*/
class Phone {
//品牌
String brand;
//价格
int price;
//颜色
String color;
//打电话的方法
public void call(String name) {
System.out.println("给"+name+"打电话");
}
//发短信的方法
public void sendMessage() {
System.out.println("群发短信");
}
//玩游戏的方法
public void playGame() {
System.out.println("玩游戏");
}
}
类的调用
创建对象:
格式:类名 对象名 = new 类名();
使用:
-对象名.成员变量
-对象名.成员方法
/*
手机类的测试
*/
class Phone {
//品牌
String brand;
//价格
int price;
//颜色
String color;
//打电话的方法
public void call(String name) {
System.out.println("给"+name+"打电话");
}
//发短信的方法
public void sendMessage() {
System.out.println("群发短信");
}
//玩游戏的方法
public void playGame() {
System.out.println("玩游戏");
}
}
class PhoneDemo {
public static void main(String[] args) {
//创建手机对象
//类名 对象名 = new 类名();
Phone p = new Phone();
//直接输出成员变量值
System.out.println(p.brand+"---"+p.price+"---"+p.color);
//给成员变量赋值
p.brand = "诺基亚";
p.price = 100;
p.color = "灰色";
//再次输出
System.out.println(p.brand+"---"+p.price+"---"+p.color);
//调用方法
p.call("张三");
p.sendMessage();
p.playGame();
}
}
对象的内存图
学生类
/*
在一个java文件中写两个类:一个基本的类,一个测试类
注意:文件名称和测试类名称一致
如何使用呢?
创建对象使用
如何创建对象
格式:类名 对象名 = new 类名();
如何使用成员变量
对象名.变量名
如何使用成员方法
对象名.方法名(...)
*/
//这是学生类
class Student {
//姓名
String name; //默认值null
//年龄
int age; //默认值0
//地址
String address; //默认值null
//学习
public void study() {
System.out.println("学生爱学习");
}
//吃饭
public void eat() {
System.out.println("学习饿了,要吃饭");
}
//睡觉
public void sleep() {
System.out.println("学习累了,要睡觉");
}
}
//这是学生测试类
class StudentDemo {
public static void main(String[] args) {
//类名 对象名 = new 类名();
Student s = new Student();
//输出成员变量值
//System.out.println(s.name);
//System.out.println(s.age);
//System.out.println(s.address);
//改进写法
System.out.println(s.name+"---"+s.age+"---"+s.address);
//给成员变量赋值
s.name = "张三";
s.age = 18;
s.address = "北京";
//赋值后的输出
System.out.println(s.name+"---"+s.age+"---"+s.address);
//调用方法
s.study();
s.eat();
s.sleep();
}
}
Day7
成员变量和局部变量的区别
在类中的位置不同
-成员变量:在类中方法外
-局部变量:在方法定义中或者方法声明上
在内存中的位置不同
-成员变量:在堆内存
-局部变量:在栈内存
生命周期不同
-成员变量:随着对象的创建而存在,随着对象的消失而消失
-局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
初始化值不同
-成员变量:有默认初始化值
-局部变量:没有默认初始化值,必须定义,赋值,然后才能使用
注意事项:
局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则
匿名对象
就是没有名字的对象
匿名对象的应用场景:
调用方法,仅仅只调用一次的时候
注意:调用多次的时候,不适合
好处:匿名对象调用完毕就是垃圾。可以被垃圾回收器回收
匿名对象可以作为实际参数传递
private关键字
是一个权限修饰符
可以修饰成员变量和成员方法
被其修饰的成员只能在本类中被访问
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
class Demo {
//用private修饰
private int num = 10;
public void show() {
System.out.println(num);
}
private void method() {
System.out.println("method");
}
public void function() {
method();
}
}
class PrivateDemo {
public static void main(String[] args) {
Demo d = new Demo();
//不能访问私有的成员变量
//System.out.println(d.num);
d.show();
//不能访问私有的成员方法
//d.method();
d.function();
}
}
对数据进行限制
class Student {
//姓名
String name;
//年龄
private int age; //对年龄进行限制
//写一个方法对数据进行限制
public void setAge(int a) {
if(a < 0 || a > 120) {
System.out.println("你给的年龄有问题");
}else {
age = a;
}
}
//show()方法,显示所有成员变量值
public void show() {
System.out.println("姓名:"+name);
System.out.println("年龄:"+age);
}
}
class StudentDemo { //测试类
public static void main(String[] args) {
//创建学生对象
Student s = new Student();
s.show();
System.out.println("--------------");
//给成员变量赋值
s.name = "张三";
//s.age = 27; //私有,不可访问
s.setAge(27);
s.show();
System.out.println("--------------");
//给age赋值
//s.age = -27; //这个数据是不合理的
//通过方法给值
s.setAge(-27);
s.show();
System.out.println("--------------");
}
}
封装private最常见的应用
-把成员变量用private修饰
-提供对应的getXxx()/setXxx()方法 set赋值,用来输入,get获取值,用来输出
class Student {
//姓名
private String name;
//年龄
private int age;
//姓名获取值
public String getName() {
return name;
}
//姓名设置值
public void setName(String n) {
name = n;
}
//年龄获取值
public int getAge() {
return age;
}
//年龄赋值
public void setAge(int a) {
age = a;
}
}
//测试类
class StudentTest {
public static void main(String[] args) {
//创建学生对象
Student s = new Student();
//使用成员变量
//错误:被私有修饰了,外界不能直接访问了
//System.out.println(s.name+"---"+s.age);
System.out.println(s.getName()+"---"+s.getAge());
//给成员变量赋值
//s.name = "张三";
//s.age = 27;
//通过方法给赋值
s.setName("张三");
s.setAge(27);
System.out.println(s.getName()+"---"+s.getAge());
}
}
this关键字
this:是当前类的对象引用,简单的记,它就代表当前类的一个对象
注意:谁调用这个方法,在该方法内部的this就代表谁。
this的场景:
解决局部变量隐藏成员变量
class Student {
//姓名
private String name;
//年龄
private int age;
//姓名获取值
public String getName() {
return name;
}
//姓名设置值,起名字要做到见名知意
public void setName(String name) { //name = "张三";
//name = name; //变量的使用规则:就近原则
//这里是类名,目前还没有说过类似的用法,所以这个是有问题的
//这里的调用只能通过对象名
//这个对象如果存在,它应该代表的是Student的一个对象
//那么,谁能够代表当前类的对象呢? java就提供了一个关键字 this
//Student.name = name;
this.name = name;
}
//年龄获取值
public int getAge() {
return age;
}
//年龄赋值
public void setAge(int age) {
this.age = age;
}
}
//测试类
class StudentTest {
public static void main(String[] args) {
//创建学生对象
Student s = new Student();
//给成员变量赋值
s.setName("张三");
s.setAge(27);
//获取数据
System.out.println(s.getName()+"---"+s.getAge());
}
}
/*
标准的代码改进版
this:哪个对象调用那个方法,this就代表那个对象
*/
class Student {
private String name;
private int age;
public String getName() {
return name; //这里其实是隐含了this
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class StudentTest2 {
public static void main(String[] args) {
//创建一个对象
Student s1 = new Student();
s1.setName("张三");
s1.setAge(27);
System.out.println(s1.getName()+"---"+s1.getAge());
//创建第二个对象
Student s2 = new Student();
s2.setName("李四");
s2.setAge(30);
System.out.println(s2.getName()+"---"+s2.getAge());
}
}
构造方法
构造方法作用概述
给对象的数据进行初始化
构造方法格式
方法名与类名相同
没有返回值类型,连void都没有
没有具体的返回值
class Student {
private String name; //null
private int age; //0
public Student() { //创建了一个构造方法
System.out.println("这是构造方法");
}
}
class ConstructDemo {
public static void main(String[] args) {
//创建对象
Student s = new Student();
System.out.println(s); //输出这是构造方法跟地址值,说明经过了上边的public Student
}
}
构造方法注意事项
如果你不提供构造方法,系统会给出默认构造方法
如果你提供了构造方法,系统将不再提供
构造方法也是可以重载的
构造方法赋值的形式
public class People {
//姓名
String name;
//年龄
int age;
//住址
String address;
//构造方法无参
public People(){ }
//有参
public People(String name,int age){
this.name = name;
this.age = age;
}
//三个参数
public People(String name,int age,String address){
this.age = age;
this.name = name;
this.address = address;
}
//show打印所有信息
public void show(){
System.out.println("姓名:"+name+" 年龄:"+age+" 住址:"+address);
}
}
class PeopleText{
public static void main(String[] args) {
//创建对象无参
People p = new People();
p.name = "张三";
p.age = 18;
p.address = "山东省";
p.show();
//两个参数的
People p1 = new People("李四",15);
p1.address = "北京省";
p1.show();
//三个参数的
People p2 = new People("王五",15,"山东省");
p2.show();
}
}
给成员变量赋值有两种方式:
-setXxx()
-构造方法
成员方法
根据返回值:
-void类型
-非void类型
形式参数:
-空参方法
-非空参方法
四种方式的调用:
class Student {
public String getString() {
return "helloworld";
}
public void show() {
System.out.println("show");
}
public void method(String name) {
System.out.println(name);
}
public String function(String s1,String s2) {
return s1+s2;
}
}
class StudentDemo {
public static void main(String[] args) {
//创建对象
Student s = new Student();
//调用无参无返回值方法
s.show();
//调用无参有返回值方法
String result = s.getString();
System.out.println(result);
//调用带参无返回值的方法
s.method("张三");
//调用带参带返回值的方法
String result2 = s.function("hello","world");
System.out.println(result2);
}
}
类分为成员变量,构造方法,成员方法
成员变量
构造方法
-无参构造方法
-带参构造方法
成员方法
-getXxx()
-setXxx()
类的标准写法
/*
学生类:
成员变量:
name,age
构造方法:
无参,带两个参
成员方法:
getXxx()/setXxx()
show():输出该类的所有成员变量值
给成员变量赋值:
A:setXxx()方法
B:构造方法
输出成员变量值的方式:
A:通过getXxx()分别获取然后拼接
B:通过调用show()方法搞定
*/
class Student {
//姓名
private String name;
//年龄
private int age;
//构造方法
public Student() {
}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//输出所有的成员变量值
public void show() {
System.out.println(name+"---"+age);
}
}
//测试类
class StudentTest {
public static void main(String[] args) {
//方式1给成员变量赋值
//无参构造+setXxx()
Student s1 = new Student();
s1.setName("张三");
s1.setAge(27);
//输出值
System.out.println(s1.getName()+"---"+s1.getAge());
s1.show();
System.out.println("----------------------------");
//方式2给成员变量赋值
Student s2 = new Student("李四",30);
System.out.println(s2.getName()+"---"+s2.getAge());
s2.show();
}
}
注意:
-给成员变量赋值有两种方式,可以只写一种,推荐使用setXxx()方法,单个输入更灵活
-如果不单独获取数据,可以不写getXxx()方法
类的初始化过程
Student s = new Student();在内存中做了哪些事情
-加载Student.class文件进内存
-在栈内存为s开辟空间
-在堆内存为学生对象开辟空间
-对学生对象的成员变量进行默认初始化
-对学生对象的成员变量进行显示初始化
-通过构造方法对学生对象的成员变量赋值
-学生对象初始化完毕,把对象地址赋值给s变量
static关键字
可以修饰成员变量和成员方法
static关键字特点
-随着类的加载而加载
-优先于对象存在
-被类的所有对象共享(这也是我们判断是否使用静态关键字的条件)
-可以通过类名调用
可以通过类名和对象名调用
class Student {
//非静态变量
int num = 10;
//静态变量
static int num2 = 20;
}
class StudentDemo {
public static void main(String[] args) {
Student s = new Student();
System.out.println(s.num);
System.out.println(Student.num2); //可以通过类名调用
System.out.println(s.num2); //可以通过对象调用
}
}
/*
定义一个人类
姓名和年龄都是变化的,因为每个人的姓名和年龄是不同的。
但是,我们想到的都是中国人,他们的国籍是一样的。
一样的国籍,我每次创建对象,在堆内存都要开辟这样的空间,很浪费
针对多个对象有共同的这样的成员变量值的时候,
Java就提高了一个关键字来修饰:static。
*/
class Person {
//姓名
String name;
//年龄
int age;
//国籍
static String country; //静态修饰
public Person(){}
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public Person(String name,int age,String country) {
this.name = name;
this.age = age;
this.country = country;
}
public void show() {
System.out.println("姓名:"+name+",年龄:"+age+",国籍:"+country);
}
}
class PersonDemo {
public static void main(String[] args) {
//创建对象1
Person p1 = new Person("邓丽君",16,"中国");
p1.show();//输出姓名:邓丽君,年龄16,国籍中国
//创建对象2
Person p2 = new Person("杨幂",22); //因为country是静态static修饰的,相当于默认值,所以这个不赋值也是中国
p2.show();//输出姓名:杨幂,年龄22,国籍中国
//创建对象3
Person p3 = new Person("凤姐",20);
p3.show(); //同上
p3.country = "美国";
p3.show();//输出姓名:凤姐,年龄20,国籍美国
p1.show();//输出姓名:邓丽君,年龄16,国籍美国
p2.show();//输出姓名:杨幂,年龄22,国籍美国
//p1 p2的国际为什么改变,因为用的同一个静态修饰即默认值,在内存中用的同一块地址,所以会改变
}
}
static关键字注意事项
-在静态方法中是没有this关键字的
-静态方法只能访问静态的成员变量和静态的成员方法
/*static关键字注意事项
在静态方法中是没有this关键字的
如何理解呢?
静态是随着类的加载而加载,this是随着对象的创建而存在。
静态比对象先存在。
静态方法只能访问静态的成员变量和静态的成员方法
静态方法:
成员变量:只能访问静态变量
成员方法:只能访问静态成员方法
非静态方法:
成员变量:可以是静态的,也可以是非静态的
成员方法:可是是静态的成员方法,也可以是非静态的成员方法。
简单记:
静态只能访问静态。
*/
class Teacher {
public int num = 10;
public static int num2 = 20;
public void show() {
System.out.println(num); //隐含的告诉你访问的是成员变量
System.out.println(this.num); //明确的告诉你访问的是成员变量
System.out.println(num2);
//function();
//function2();
}
public static void method() {
//无法从静态上下文中引用非静态 变量 num
//System.out.println(num);
System.out.println(num2);
//无法从静态上下文中引用非静态 方法 function()
//function();
function2();
}
public void function() {
}
public static void function2() {
}
}
class TeacherDemo {
public static void main(String[] args) {
//创建对象
Teacher t = new Teacher();
t.show();
System.out.println("------------");
t.method();
}
}
静态变量和成员变量的区别
所属不同
-静态变量属于类,所以也称为为类变量
-成员变量属于对象,所以也称为实例变量(对象变量)
内存中位置不同
-静态变量存储于方法区的静态区
-成员变量存储于堆内存
内存出现时间不同
-静态变量随着类的加载而加载,随着类的消失而消失
-成员变量随着对象的创建而存在,随着对象的消失而消失
调用不同
-静态变量可以通过类名调用,也可以通过对象调用
-成员变量只能通过对象名调用
main方法详解
main方法的格式讲解:
public static void main(String[] args) {...}
public:公共的,访问权限是最大的。由于main方法是被jvm调用,所以权限要够大
static:静态的,不需要创建对象,通过类名就可以,方便jvm的调用
void:因为我们曾经说过,方法的返回值是返回给调用者,而main方法是被jvm调用,你返回内容给jvm没有意义
main:是一个常见的方法入口。我见过的语言都是以main作为入口
String[] args:这是一个字符串数组,这个东西早期是为了接收键盘录入的数据的
格式是:java MainDemo hello world java
Day8
制作一个代码说明书
/*
我想要对数组进行操作
如何制作一个说明书呢
写一个工具类
对这个类加入文档注释
怎么加
加些什么东西
用工具解析文档注释
javadoc工具
格式
javadoc -d 目录 -author -version ArrayTool.java
目录:就可以写一个文件夹的路径
制作帮助文档出错:
找不到可以文档化的公共或受保护的类:告诉我们类的权限不够
*/
class ArrayDemo {
public static void main(String[] args) {
//定义数组
int[] arr = {28,55,37,46,19};
//遍历
ArrayTool.printArray(arr);
//获取最值
int max = ArrayTool.getMax(arr);
System.out.println("max:"+max);
//获取55的索引值
int index = ArrayTool.getIndex(arr,55);
System.out.println("index:"+index);
}
}
/**
* 这是针对数组进行操作的工具类
* @author 张三
* @version V1.0
*/
public class ArrayTool {
//把构造方法私有,外界就不能在创建对象了
/**
* 这是私有构造
*/
private ArrayTool(){}
/**
* 这是遍历数组的方法,遍历后的格式是:[元素1, 元素2, 元素3, ...]
* @param arr 这是要被遍历的数组
*/
public static void printArray(int[] arr) {
System.out.print("[");
for(int x=0; x max) {
max = arr[x];
}
}
return max;
}
/**
* 获取指定元素在数组中第一次出现的索引,如果元素不存在,就返回-1
* @param arr 被查找的数组
* @param value 要查找的元素
* @return 返回元素在数组中的索引,如果不存在,返回-1
*/
public static int getIndex(int[] arr,int value) {
int index = -1;
for(int x=0; x
上列代码生成的说明书
如何使用JDK的帮助文档
1:打开帮助文档
2:点击显示,找到索引,看到输入框
3:知道你要找谁?以Scanner举例
4:在输入框里面输入Scanner,然后回车
5:看包
java.lang包下的类不需要导入,其他的全部需要导入。
要导入:java.util.Scanner
6:再简单的看看类的解释和说明,别忘了看看该类的版本
7:看类的结构
成员变量 字段摘要
构造方法 构造方法摘要
成员方法 方法摘要
8:学习构造方法
有构造方法 就创建对象
没有构造方法 成员可能都是静态的
9:看成员方法
左边
是否静态:如果静态,可以通过类名调用
返回值类型:人家返回什么,你就用什么接收
右边
看方法名:方法名称不要写错
参数列表:人家要什么,你就给什么;人家要几个,你就给几个
Random方法
第一步先导包:import java.util.Random;
第二步创建对象:Random r = new Random(); //r 和 num 为变量名,可以改
第三步使用: int num = r.nextInt(20)+1; //20表示从0开始生成20个数据,+1表示从1-20
猜数字小游戏
import java.util.Random;
import java.util.Scanner;
public class CaiNumber {
//猜数字范围(1-20)
/*
* 分析:系统生成一个随机数
* 用户进行输入一个数
* 进行比较
* 大了
* 小了
* 猜中了
* 不确定多少次猜中,用while,猜中就break;
* */
public static void main(String[] args) {
Random r = new Random();
System.out.println("系统生成随机数");
int goodNum = r.nextInt(20)+1;
//System.out.println(goodNum);
//定义死循环进行猜数字
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("用户输入猜测的数");
int num = sc.nextInt();
if (num < goodNum){
System.out.println("猜小了,请继续");
}else if (num > goodNum){
System.out.println("猜大了,请继续");
}else {
System.out.println("猜中了");
break;
}
}
}
}
代码块
在Java中,使用{}括起来的代码被称为代码块,根据其位置和声明的不同,可以分为
-局部代码块
-构造代码块
-静态代码块
-同步代码块(多线程讲解)
局部代码块
在方法中出现;限定变量生命周期,及早释放,提高内存利用率
构造代码块
在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
静态代码块 在类中方法外出现,加了static修饰
在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且值执行一次
静态代码块,构造代码块,构造方法的顺序问题
静态代码块 > 构造代码块 > 构造方法
静态代码块:只执行一次
构造代码块:每次调用构造方法都执行
/*
写程序的执行结果。
输出结果:
main函数静态方法
我是main方法
Student 静态代码块
Student 构造代码块
Student 构造方法
Student 构造代码块
Student 构造方法
先调用main方法中的静态代码块,在调用main方法,创建对象s1,执行Student类中的方法,先执行静态,在执行构造代码块,最后执行构造方法,在创建对象s2,执行Student类中的方法,静态只执行一次,所以只执行构造代码块和构造方法
*/
class Student {
static {
System.out.println("Student 静态代码块");
}
{
System.out.println("Student 构造代码块");
}
public Student() {
System.out.println("Student 构造方法");
}
}
class StudentDemo {
static {
System.out.println("main函数静态方法");
}
public static void main(String[] args) {
System.out.println("我是main方法");
Student s1 = new Student(); //创建对象
Student s2 = new Student();
}
}
继承
继承概述:
把多个类中相同的内容给提取出来定义到一个类中。
如何实现继承呢?
Java提供了关键字:extends
格式:
class 子类名 extends 父类名 {}
好处:
-提高了代码的复用性
-提高了代码的维护性
-让类与类之间产生了关系,是多态的前提
类与类产生了关系,其实也是继承的一个弊端:
类的耦合性增强了。
开发的原则:低耦合,高内聚。
耦合:类与类的关系
内聚:就是自己完成某件事情的能力
//使用继承前
class Student {
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
class Teacher {
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
//使用继承后
class Person {
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
class Student extends Person {} //继承格式
class Teacher extends Person {}
class ExtendsDemo {
public static void main(String[] args) {
Student s = new Student();
s.eat();
s.sleep();
System.out.println("-------------");
Teacher t = new Teacher();
t.eat();
t.sleep();
}
}
Java继承的特点
-Java只支持单继承,不支持多继承
-Java支持多层继承(继承体系)
class Father {}
class Mother {}
class Son exnteds Father {} //正确的
class Son extends Father,Mother {} // 错误的,不可以多继承
*/
class GrandFather {
public void show() {
System.out.println("我是爷爷");
}
}
class Father extends GrandFather { //老子继承爷爷的
public void method(){
System.out.println("我是老子");
}
}
class Son extends Father {} //儿子继承老子的,构成多层继承
class ExtendsDemo2 {
public static void main(String[] args) {
Son s = new Son();
s.method(); //使用父亲的
s.show(); //使用爷爷的
}
}
Java继承中的成员关系
成员变量
子类的成员变量名称和父类中的成员变量名称不一样,通过名称访问
子类的成员变量名称和父类中的成员变量名称一样
子类的方法访问变量的查找顺序:
-在子类方法的局部范围找,有就使用
-在子类的成员范围找,有就使用
-在父类的成员范围找,有就使用
-找不到,就报错
构造方法
子类的构造方法默认会去访问父类的无参构造方法
是为了子类访问父类数据的初始化
父类中如果没有无参构造方法,怎么办
-子类通过super去明确调用带参构造
-子类通过this调用本身的其他构造,但是一定会有一个去访问了父类的构造
-让父类提供无参构造
成员方法
子类的成员方法和父类中的成员方法名称不一样,通过名称
子类的成员方法和父类中的成员方法名称一样,
通过子类对象访问一个方法的查找顺序:
-在子类中找,有就使用
-在父类中找,有就使用
-找不到,就报错
继承的注意事项
-子类只能继承父类所有非私有的成员(成员方法和成员变量)
-子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法
-不要为了部分功能而去继承
什么时候考虑用继承
继承其实体现的是一种关系:"is a"。
Person //人
Student //学生
Teacher //老师
老师是人,学生也是人,就考虑继承
水果
苹果 //是水果的一种
香蕉 //是水果的一种
采用假设法
如果有两个类A,B,只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承
类的组成
-成员变量:
-构造方法:
-成员方法:
在子类方法中访问一个变量的查找顺序:
-在子类方法的局部范围找,有就使用
-在子类的成员范围找,有就使用
-在父类的成员范围找,有就使用
-如果还找不到,就报错
super关键字
代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)
this 代表本类对应的引用
用法:
调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
调用构造方法
this(...) 调用本类的构造方法
super(...) 调用父类的构造方法
调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
继承中构造方法的关系
子类中所有的构造方法默认都会访问父类中空参数的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据,所以,子类初始化之前,一定要先完成父类数据的初始化
注意:子类每一个构造方法的第一条语句默认都是:super();
class Father {
int age;
public Father() {
System.out.println("Father的无参构造方法");
}
public Father(String name) {
System.out.println("Father的带参构造方法");
}
}
class Son extends Father {
public Son() {
//super();
System.out.println("Son的无参构造方法");
}
public Son(String name) {
//super();
System.out.println("Son的带参构造方法");
}
}
class ExtendsDemo6 {
public static void main(String[] args) {
//创建对象
Son s = new Son();
System.out.println("------------");
Son s2 = new Son("张三"); //不管子类是有参还是无参,都走父类的无参构造
}
}
//运行结果
Father的无参构造方法
Son的无参构造方法
------------
Father的无参构造方法
Son的带参构造方法
如果父类没有无参构造方法,那么子类的构造方法会报错
如何解决
-在父类中加一个无参构造方法
-通过使用super关键字去显示的调用父类的带参构造方法
-子类通过this去调用本类的其他构造方法
子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化
注意事项:
this(...)或者super(...)必须出现在第一条语句上
如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上
class Father {
/*
public Father() {
System.out.println("Father的无参构造方法");
}
*/
public Father(String name) {
System.out.println("Father的带参构造方法");
}
}
class Son extends Father {
public Son() {
super("随便给");
System.out.println("Son的无参构造方法");
//super("随便给");
}
public Son(String name) {
//super("随便给");
this();
System.out.println("Son的带参构造方法");
}
}
class ExtendsDemo7 {
public static void main(String[] args) {
Son s = new Son();
System.out.println("----------------");
Son ss = new Son("张三");
}
}
//结果
Father的带参构造方法
Son的无参构造方法
----------------
Father的带参构造方法
Son的无参构造方法
Son的带参构造方法
方法重写
方法重写:子类中出现了和父类中方法声明一模一样的方法
方法重载:本类中出现的方法名一样,参数列表不同的方法,与返回值无关
子类对象调用方法的时候:先找子类本身,再找父类
方法重写的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
/*
手机都有通话功能
新手机通话完成后会显示通话时间
*/
class Phone {
public void call(String name) {
System.out.println("给"+name+"打电话");
}
}
class NewPhone extends Phone {
public void call(String name) {
//System.out.println("给"+name+"打电话");
super.call(name); //调用父类中的方法
System.out.println("通话时长");
}
}
class ExtendsDemo9 {
public static void main(String[] args) {
NewPhone np = new NewPhone();
np.call("张三"); //结果:给张三打电话,通话时长
}
}
方法重写的注意事项
-父类中私有方法不能被重写
因为父类私有方法子类根本就无法继承
-子类重写父类方法时,访问权限不能更低
最好就一致
-父类静态方法,子类也必须通过静态方法进行重写
子类重写父类方法的时候,最好声明一模一样
练习
1:方法重写和方法重载的区别?方法重载能改变返回值类型吗?
方法重写:
在子类中,出现和父类中一模一样的方法声明的现象。
方法重载:
同一个类中,出现的方法名相同,参数列表不同的现象。
方法重载能改变返回值类型,因为它和返回值类型无关。
Override:方法重写
Overload:方法重载
2:this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。
this:代表当前类的对象引用
super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员)
场景:
成员变量:
this.成员变量
super.成员变量
构造方法:
this(...)
super(...)
成员方法:
this.成员方法
super.成员方法
继承版猫狗案例
/*
* 猫狗案例
* 分析:
* 猫类:
* 成员变量:
* 姓名,年龄,颜色
* 构造方法:
* 有参跟无参
* 成员方法:
* 吃饭,睡觉,捉老鼠(猫特有)
* 狗类:
* 成员变量:
* 姓名,年龄,颜色
* 构造方法:
* 有参跟无参
* 成员方法:
* 吃饭,睡觉,看门(狗特有)
*
* 把公共部门定义成一个类
* 动物类:
* 成员变量:
* 姓名,年龄,颜色
* 构造方法:
* 有参跟无参
* 成员方法:
* 吃饭,睡觉
* */
class Animal {
//姓名
private String name;
// 年龄
private int age;
// 颜色
private String color;
//构造方法
public Animal() {
} //无参
public Animal(String name, int age, String color) { //有参
this.name = name;
this.age = age;
this.color = color;
}
//成员方法:get,sat,吃饭,睡觉
//姓名
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//年龄
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//颜色
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//吃饭
public void eat() {
System.out.println(name + "吃饭");
}
//睡觉
public void sleep() {
System.out.println(name + "睡觉");
}
}
//猫类
class Cat extends Animal{
//无参构造
public Cat(){}
//有参构造
public Cat(String name,int age,String color){
super(name, age, color);
}
public void playGame(){
System.out.println(super.getName()+"捉老鼠"); //调用父类的成员方法,输出姓名
}
}
//狗类
class Dog extends Animal{
//无参构造
public Dog(){}
//有参构造
public Dog(String name,int age,String color){
super(name, age, color);
}
public void lookDoor(){
System.out.println(super.getName()+"看门");
}
}
class Text{ //测试类
public static void main(String[] args) {
//猫无参
Cat cat = new Cat();
cat.setName("小花");
cat.setColor("花色");
cat.setAge(18);
cat.eat();
cat.playGame();
System.out.println(cat.getName()+cat.getAge()+cat.getColor());
System.out.println("----------");
//猫有参
Cat cat1 = new Cat("甜甜",15,"蓝色");
cat1.playGame();
cat.sleep();
System.out.println(cat1.getName()+cat1.getAge()+cat1.getColor());
System.out.println("----------");
//狗无参
Dog dog = new Dog();
dog.setName("小黑");
dog.setAge(17);
dog.setColor("黑色");
dog.eat();
dog.lookDoor();
System.out.println(dog.getName()+dog.getAge()+dog.getColor());
System.out.println("----------");
//狗类有参
Dog dog1 = new Dog("小白",13,"白色");
dog1.eat();
dog1.lookDoor();
System.out.println(dog1.getName()+dog1.getAge()+dog1.getColor());
}
}
/*
结果:
小花吃饭
小花捉老鼠
小花18花色
----------
甜甜捉老鼠
小花睡觉
甜甜15蓝色
----------
小黑吃饭
小黑看门
小黑17黑色
----------
小白吃饭
小白看门
小白13白色
*/
Day9
final关键字
继承的代码体现
由于继承中方法有一个现象:方法重写
所以,父类的功能,就会被子类给覆盖掉,有些时候,我们不想让子类去覆盖掉父类的功能,只能让他使用,这个时候,针对这种情况,Java就提供了一个关键字:final
final:最终的意思,常见的是它可以修饰类,方法,变量
class Fu {
//public void show() { 将show改为用final修饰
public final void show {
System.out.println("这里是绝密资源,任何人都不能修改");
}
}
class Zi extends Fu {
//Zi中的show就无法覆盖Fu中的show
public void show() {
System.out.println("这是一堆垃圾");
}
}
class ZiDemo {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
final可以修饰类,方法,变量
特点:
final修饰类,该类不可以被继承
final修饰方法,该方法不能被重写
final修饰变量,该变量不能被重新赋值
final也可以修饰局部变量
基本数据类型的值不可以改变
引用数据类型的地址值不可以改变,但是该对象堆内存的值可以改变
final修饰变量初始化时机
被final修饰的变量只能被赋值一次
在构造方法完成前(非静态的常量)
多态
是指同一个事物(对象),在不同时刻表现出来的不同的状态、
例:猫是猫,猫也是动物
多态的前提:
要有继承关系
要有方法重写
要有父类引用指向子类对象
父类 fu = new 子类();
用代码体现一下多态
class Fu{
public void show(){
System,out.println("这是父类的show");
}
}
class Zi extends Fu{ //要有继承关系
public void show(){
System,out.println("这是子类的show"); //要有方法重写
}
}
class DuiTai{
public static void main(String[] args){
Fu fu = new Zi(); //要有父类引用指向子类对象
}
}
多态中的成员访问特点
成员变量
编译看左边,运行看左边
构造方法
创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化
成员方法
编译看左边,运行看右边
静态方法
编译看左边,运行看左边
(静态和类相关,算不上重写,所以,访问还是左边的)
由于成员方法存在方法重写,所以它运行看右边
class Fu {
public int num = 100;
public void show() {
System.out.println("show Fu");
}
public static void function() { //静态
System.out.println("function Fu");
}
}
class Zi extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method zi");
}
public static void function() { //静态
System.out.println("function Zi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//要有父类引用指向子类对象。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num); //输出100,成员变量运行看左边
//找不到符号,成员变量编译看左边
//System.out.println(f.num2);
f.show(); //输出showZi,成员方法运行看右边,因为有方法重写
//找不到符号,成员方法编译看左边,父类中没有,所以找不到
//f.method();
f.function(); //输出funcyion Fu,静态方法编译看左边,输出看左边
}
}
多态的好处
提高了代码的维护性(由继承保证)
提高了代码的扩展性(由多态保证)
class Animal {
public void eat(){
System.out.println("eat");
}
public void sleep(){
System.out.println("sleep");
}
}
class Dog extends Animal {
public void eat(){
System.out.println("狗吃肉");
}
public void sleep(){
System.out.println("狗站着睡觉");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
public void sleep() {
System.out.println("猫趴着睡觉");
}
}
class Pig extends Animal {
public void eat() {
System.out.println("猪吃白菜");
}
public void sleep() {
System.out.println("猪侧着睡");
}
}
//针对动物操作的工具类
class AnimalTool {
private AnimalTool(){}
/*
//调用猫的功能
public static void useCat(Cat c) {
c.eat();
c.sleep();
}
//调用狗的功能
public static void useDog(Dog d) {
d.eat();
d.sleep();
}
//调用猪的功能
public static void usePig(Pig p) {
p.eat();
p.sleep();
}
*/
public static void useAnimal(Animal a) { //因为每添加一个动物类就要改工具类,所以直接改成动物类
a.eat();
a.sleep();
}
}
class DuoTaiDemo2 {
public static void main(String[] args) {
//我喜欢猫,就养了一只
Cat c = new Cat();
c.eat();
c.sleep();
//我很喜欢猫,所以,又养了一只
Cat c2 = new Cat();
c2.eat();
c2.sleep();
//我特别喜欢猫,又养了一只
Cat c3 = new Cat();
c3.eat();
c3.sleep();
//...
System.out.println("--------------");
//问题来了,我养了很多只猫,每次创建对象是可以接受的
//但是呢?调用方法,你不觉得很相似吗?仅仅是对象名不一样。
//我们准备用方法改进
//调用方式改进版本
//useCat(c);
//useCat(c2);
//useCat(c3);
//AnimalTool.useCat(c);
//AnimalTool.useCat(c2);
//AnimalTool.useCat(c3);
AnimalTool.useAnimal(c);
AnimalTool.useAnimal(c2);
AnimalTool.useAnimal(c3);
System.out.println("--------------");
//我喜欢狗
Dog d = new Dog();
Dog d2 = new Dog();
Dog d3 = new Dog();
//AnimalTool.useDog(d);
//AnimalTool.useDog(d2);
//AnimalTool.useDog(d3);
AnimalTool.useAnimal(d);
AnimalTool.useAnimal(d2);
AnimalTool.useAnimal(d3);
System.out.println("--------------");
//我喜欢宠物猪
//定义一个猪类,它要继承自动物,提供两个方法,并且还得在工具类中添加该类方法调用
Pig p = new Pig();
Pig p2 = new Pig();
Pig p3 = new Pig();
//AnimalTool.usePig(p);
//AnimalTool.usePig(p2);
//AnimalTool.usePig(p3);
AnimalTool.useAnimal(p);
AnimalTool.useAnimal(p2);
AnimalTool.useAnimal(p3);
System.out.println("--------------");
//我喜欢宠物狼,老虎,豹子...
//定义对应的类,继承自动物,提供对应的方法重写,并在工具类添加方法调用
//前面几个必须写,我是没有意见的
//但是,工具类每次都改,麻烦不
//我就想,你能不能不改了
//太简单:把所有的动物都写上。问题是名字是什么呢?到底哪些需要被加入呢?
//改用另一种解决方案。
}
/*
//调用猫的功能
public static void useCat(Cat c) {
c.eat();
c.sleep();
}
//调用狗的功能
public static void useDog(Dog d) {
d.eat();
d.sleep();
}
*/
}
多态的弊端
不能使用子类特有的功能
class Fu{
public void show(){
System.out.println(show 父类);
}
}
class Zi extends Fu{
public void show(){
System.out.println(show 子类);
}
public void eat(){
System.out.println("吃饭");
}
}
class DuoTai{
public static void main(String[] args){
Fu fu = new Zi();
fu.show(); //可以执行
fu.eat(); //不可以执行,父类不能访问子类特有的功能
}
}
如何解决多态的弊端:
-可以新建一个子类对象调用子类特有的方法
-向下转型
Zi z = (Zi) f; //要求该f必须能转化成Zi的
对象间的转型问题
向上转型:
Fu f = new Zi();
向下转型:
Zi z = (Zi)f; //要求该f必须是能够转换为Zi的
错误提示:ClassCastException:类型转换异常,一般在多态的向下转型中容易出现
多态版猫狗案例
class DongWu{ //动物类
//吃饭
public void eat(){
System.out.println("吃饭");
}
//睡觉
public void sleep(){
System.out.println("睡觉");
}
}
class Mao extends DongWu{ //定义猫类继承动物类
//吃饭
public void eat(){
System.out.println("猫吃鱼");
}
//睡觉
public void sleep(){
System.out.println("猫趴着睡觉");
}
//猫玩游戏
public void playGame(){
System.out.println("猫玩捉迷藏");
}
}
class Gou extends DongWu{ //定义狗类继承动物类
//吃饭
public void eat(){
System.out.println("狗吃肉");
}
//睡觉
public void sleep(){
System.out.println("狗站着睡觉");
}
//看门
public void lookDoor(){
System.out.println("狗看门");
}
}
public class DuoTaiTest {
/*
* 用多态实现猫狗案例
* 分析:
* 多态要有继承
* 多态要有父类指向子类对象
* 要有方法重写
* */
public static void main(String[] args) {
//将动物定义为狗
DongWu dw = new Gou();
dw.eat();
dw.sleep();
//无法执行dw.lookDoor
//还原为狗
Gou g = (Gou)dw;
g.lookDoor();
System.out.println("--------");
dw = new Mao();
dw.sleep();
dw.eat();
Mao m = (Mao)dw;
m.playGame();
}
}
练习
/*
看程序写结果:先判断有没有问题,如果没有,写出结果
*/
class Fu {
public void show() {
System.out.println("fu show");
}
}
class Zi extends Fu {
public void show() {
System.out.println("zi show");
}
public void method() {
System.out.println("zi method");
}
}
class DuoTaiTest3 {
public static void main(String[] args) {
Fu f = new Zi();
//找不到符号
//f.method(); //有问题,多态中成员方法编译看左边,父类中没有method方法,所以报错,找不到符号
f.show(); //可以运行,编译看左边,父类中有show方法,运行看右边,输出右边的子类show,子类重写父类
}
}
多态的成员访问特点:
方法:编译看左边,运行看右边
继承的时候:
子类中有和父类中一样的方法,叫重写
子类中没有父亲中出现过的方法,方法就被继承过来了
/*
看程序写结果:先判断有没有问题,如果没有,写出结果
*/
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
/*
public void show() { //被继承,相当于有
show2();
}
*/
public void show2() {
System.out.println("爱");
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest4 {
public static void main(String[] args) {
A a = new B();
a.show(); //打印爱
B b = new C();
b.show(); //打印你
}
}
抽象类
抽象类得声明格式:用abstract修饰
例:abstract class Person
抽象类的概述:
动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的,我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须得是抽象类
抽象类的特点:
抽象类和抽象方法必须用abstract关键字修饰
抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
抽象类不能实例化,因为他不是具体的
抽象类有构造方法,用于子类访问父类数据的初始化
抽象的子类
抽象类,可以不重写父类的抽象方法
具体类,必须重写父类所有的抽象方法
抽象类的实例化其实是靠具体的子类实现的。是多态的方式
Animal a = new Cat();
//abstract class Animal //抽象类的声明格式
abstract class Animal {
//抽象方法
//public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体
public abstract void eat(); //空方法体
public Animal(){}
}
//子类是抽象类
abstract class Dog extends Animal {}
//子类是具体类
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼"); //就需要重写父类的所有抽象方法
}
}
class AbstractDemo {
public static void main(String[] args) {
//创建对象
//Animal是抽象的; 无法实例化
//Animal a = new Animal();
//可以通过多态的方式实现抽象类的实例化
Animal a = new Cat();
a.eat();
}
}
抽象类的成员特点:
成员变量:既可以是变量,也可以是常量
构造方法:有,用于子类访问父类数据的初始化
成员方法:既可以是抽象的,也可以是非抽象的
抽象类的成员方法特性:
抽象方法 强制要求子类做的事情
非抽象方法 子类继承的事情,提高代码复用性
抽象类猫狗案例
猫狗案例
具体事物:猫,狗
共性:姓名,年龄,吃饭
分析:从具体到抽象
猫:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭(猫吃鱼)
狗:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭(狗吃肉)
因为有共性的内容,所以就提取了一个父类。动物。
但是又由于吃饭的内容不一样,所以吃饭的方法是抽象的,
而方法是抽象的类,类就必须定义为抽象类。
抽象动物类:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭();
实现:从抽象到具体
动物类:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭();
狗类:
继承自动物类
重写吃饭();
猫类:
继承自动物类
重写吃饭();
代码实现
/*
* 抽象类实现猫狗案例
*
* */
abstract class Animal { //创建抽象类动物
//姓名
private String name;
//年龄
private int age;
//构造方法,无参,有参
public Animal(){}
public Animal(String name,int age){
this.name = name;
this.age = age;
}
//成员方法,get和sat
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
//抽象方法
abstract void eat();
}
//定义具体类猫
class Cat extends Animal{
//成员变量继承
//构造方法
public Cat(){}
public Cat(String name,int age){
super(name, age);
}
//成员方法
public void eat(){
System.out.println(super.getName()+"吃鱼");
}
}
//定义具体类狗
class Dog extends Animal{
//成员变量继承
//构造方法
public Dog(){}
public Dog(String name,int age){
super(name, age);
}
//成员方法
public void eat(){
System.out.println(super.getName()+"狗吃肉");
}
}
//测试类
class ChouXiangTest{
public static void main(String[] args) {
//创建对象
//无参
Cat c = new Cat();
c.setName("小花");
c.setAge(3);
c.eat();
System.out.println(c.getName()+"---"+c.getAge());
//有参
Cat c2 = new Cat("小白",5);
c2.eat();
System.out.println(c2.getName()+"---"+c2.getAge());
//多态
Animal a = new Dog();
a.setName("小黑");
a.setAge(5);
a.eat();
System.out.println(a.getName()+"----"+a.getAge());
}
}
接口
特点:
接口用关键字interface表示
interface 接口名 {}
类实现接口用implements表示
class 类名 implements 接口名 {}
接口不能实例化,按照多态的方式来实例化
接口的子类
可以是抽象类,但是意义不大
可以是具体类,要重写接口中的所有抽象方法(推荐方案)
由此可见:
A:具体类多态(几乎没有)
B:抽象类多态(常用)
C:接口多态(最常用)
//定义动物培训接口
interface AnimalTrain {
public abstract void jump();
}
//抽象类实现接口
abstract class Dog implements AnimalTrain {
}
//具体类实现接口
class Cat implements AnimalTrain {
public void jump() {
System.out.println("猫可以跳高了");
}
}
class InterfaceDemo {
public static void main(String[] args) {
//AnimalTrain是抽象的; 无法实例化
//AnimalTrain at = new AnimalTrain();
//at.jump();
AnimalTrain at = new Cat();
at.jump(); //根据方法重写的要求,执行看右边,所以输出猫的jump,猫可以跳高了
}
}
接口成员特点
成员变量:只能是常量,并且是静态的
默认修饰符:public static final //自己写出默认修饰符
构造方法:接口没有构造方法,因为接口主要是扩展功能,没有具体存在,初始化靠父类Object
成员方法:只能是抽象方法
默认修饰符:public abstract //自己写出默认修饰符
所有的类都默认继承自一个类:Object
类 Object 是类层次结构的根类,每个类都使用 Object 作为超类
接口名+Impl这种格式是接口的实现类格式
interface Inter {
public int num = 10;
public final int num2 = 20; //不写全会默认给出
public static final int num3 = 30; //最终格式
//错误: 需要<标识符>
//public Inter() {} //接口没有构造方法
//接口方法不能带有主体
//public void show() {} //说明是抽象的
//abstract void show(); //默认public
public void show(); //默认abstract
}
//接口名+Impl这种格式是接口的实现类格式
/*
class InterImpl implements Inter {
public InterImpl() {
super();
}
}
*/
class InterImpl extends Object implements Inter { //继承自Object
public InterImpl() {
super();
}
public void show() {}
}
//测试类
class InterfaceDemo2 {
public static void main(String[] args) {
//创建对象
Inter i = new InterImpl();
System.out.println(i.num);
System.out.println(i.num2);
//i.num = 100;
//i.num2 = 200;
//System.out.println(i.num); //无法为最终变量num分配值,说明是final修饰
//System.out.println(i.num2);//无法为最终变量num2分配值
System.out.println(Inter.num);
System.out.println(Inter.num2);
System.out.println("--------------");
}
}
接口成员特点
成员变量;只能是常量,并且是静态的
默认修饰符:public static final 自己手动给出
构造方法:接口没有构造方法
成员方法:只能是抽象方法
默认修饰符:public abstract 自己手动给出
所有的类都默认继承自一个类:Object
类 Object 是类层次结构的根类。每个类都使用 Object 作为超类
接口名+Impl这种格式是接口的实现类格式
interface Inter {
public int num = 10;
public final int num2 = 20; //没写的默认给出
public static final int num3 = 30; //最终格式
//错误: 需要<标识符> 没有构造方法
//public Inter() {}
//接口方法不能带有主体
//public void show() {}
//abstract void show(); //默认public
public void show(); //默认abstract
}
//接口名+Impl这种格式是接口的实现类格式
/*
class InterImpl implements Inter {
public InterImpl() {
super();
}
}
*/
class InterImpl extends Object implements Inter { //默认继承自Object类
public InterImpl() {
super();
}
public void show() {}
}
//测试类
class InterfaceDemo2 {
public static void main(String[] args) {
//创建对象
Inter i = new InterImpl();
System.out.println(i.num);
System.out.println(i.num2);
//i.num = 100;
//i.num2 = 200;
//System.out.println(i.num); //无法为最终变量num分配值是final修饰默认
//System.out.println(i.num2);//无法为最终变量num2分配值
System.out.println(Inter.num);
System.out.println(Inter.num2);
System.out.println("--------------");
}
}
类,接口之间的关系
类与类:
继承关系,只能单继承,可以多层继承
类与接口:
实现关系,可以单实现,也可以多实现,并且还可以在继承一个类的同时实现多个接口
接口与接口:
继承关系,可以单继承,也可以多继承
一个类实现多继承接口时,要重写接口多继承中的所有方法
interface Father {
public abstract void show();
}
interface Mother {
public abstract void show2();
}
interface Sister extends Father,Mother { //接口可以多继承
}
//class Son implements Father,Mother //多实现
class Son extends Object implements Father,Mother {
public void show() {
System.out.println("show son");
}
public void show2() {
System.out.println("show2 son");
}
}
class InterfaceDemo3 {
public static void main(String[] args) {
//创建对象
Father f = new Son();
f.show();
//f.show2(); //报错,方法看左边,左边没有show2
Mother m = new Son();
//m.show(); //报错,方法看左边,左边没有show
m.show2();
}
}
抽象类和接口的区别
成员区别
抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
接口:
成员变量:只可以常量
构造方法:没有
成员方法:只可以抽象
关系区别
类与类
继承,单继承
类与接口
实现,单实现,多实现
接口与接口
继承,单继承,多继承
设计理念区别
抽象类 被继承体现的是:”is a”的关系,抽象类中定义的是该继承体系的共性功能
接口 被实现体现的是:”like a”的关系,接口中定义的是该继承体系的扩展功能(特有功能)
接口版猫狗案例
/*
* 需求:利用接口实现猫狗案例跳高功能
* 分析:从具体到抽象
* 猫:
* 成员变量:姓名,年龄
* 构造方法:有参无参
* 成员方法:睡觉,吃饭
* 狗:
* 成员变量:姓名,年龄
* 构造方法:有参无参
* 成员方法:睡觉,吃饭
* 动物:
* 成员变量:姓名,年龄
* 构造方法:有参无参
* 成员方法:睡觉(){},吃饭()抽象类,猫狗吃的不一样
* 调高功能:
* 接口
* */
//实现:从抽象到具体
//调高功能
interface Jump{
//跳高功能
public abstract void jump(); //接口中只能用抽象的方法
}
//定义抽象动物类
abstract class Animal{
//成员变量
//姓名
private String name;
//年龄
private int age;
//构造方法
public Animal(){} //无参
public Animal(String name,int age){ //有参
this.name =name;
this.age = age;
}
//成员方法
//get和sat
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
//睡觉
public void sleep(){
System.out.println("睡觉");
}
//吃饭定义为抽象类
abstract void eat();
}
//定义具体类猫
class Cat extends Animal{
//成员变量继承
//构造方法
public Cat(){}
public Cat(String name,int age){
super(name, age);
}
//成员方法,继承睡觉
//重写吃饭
public void eat(){
System.out.println("猫吃鱼");
}
}
//定义具体类狗
class Dog extends Animal{
//成员变量继承
//构造方法
public Dog(){}
public Dog(String name,int age){
super(name, age);
}
//成员方法,继承睡觉
//重写吃饭
public void eat(){
System.out.println("狗吃肉");
}
}
//猫类实现跳高
class JumpImplCat extends Cat implements Jump{
//成员变量继承
//构造方法
public JumpImplCat(){}
public JumpImplCat(String name,int age){
super(name, age);
}
//成员方法继承睡觉吃饭
//跳高
public void jump(){
System.out.println("猫跳高");
}
}
//狗类实现跳高
class JumpImplDog extends Cat implements Jump{
//成员变量继承
//构造方法
public JumpImplDog(){}
public JumpImplDog(String name,int age){
super(name, age);
}
//成员方法继承睡觉吃饭
//跳高
public void jump(){
System.out.println("狗跳高");
}
}
public class JiekouText {
public static void main(String[] args) {
//测试无参构造猫
JumpImplCat cat = new JumpImplCat();
cat.setName("哆啦A梦");
cat.setAge(3);
cat.eat();
cat.sleep();
cat.jump();
System.out.println(cat.getName()+"----"+cat.getAge());
//测试有参构造狗
JumpImplDog dog = new JumpImplDog("小白",3);
dog.eat();
dog.sleep();
dog.jump();
System.out.println(dog.getName()+"-----"+dog.getAge());
}
}
Day10
引用类型作为方法的形参
类名:(匿名对象的时候其实我们已经讲过了)需要的是该类的对象
抽象类:需要的是该抽象的类子类对象
接口:需要的是该接口的实现类对象
//类名作为方法的形式参数
class Student {
public void study() {
System.out.println("Good Good Study,Day Day Up");
}
}
class StudentDemo {
public void method(Student s) { //ss; ss = new Student(); Student s = new Student();
s.study();
}
}
class StudentTest {
public static void main(String[] args) {
//需求:我要测试Student类的study()方法
Student s = new Student(); //创建对象
s.study(); //调用方法
System.out.println("----------------");
//需求2:我要测试StudentDemo类中的method()方法
StudentDemo sd = new StudentDemo();
Student ss = new Student();
sd.method(ss);
System.out.println("----------------");
//匿名对象用法
new StudentDemo().method(new Student());
}
}
//抽象类作为方法的形式参数
abstract class Person {
public abstract void study();
}
class PersonDemo {
public void method(Person p) {//p; p = new Student(); Person p = new Student(); //多态
p.study();
}
}
//定义一个具体的学生类
//抽象类作为方法的形式参数
class Student extends Person {
public void study() {
System.out.println("Good Good Study,Day Day Up");
}
}
class PersonTest {
public static void main(String[] args) {
//目前是没有办法的使用的
//因为抽象类没有对应的具体类
//那么,我们就应该先定义一个具体类
//需求:我要使用PersonDemo类中的method()方法
PersonDemo pd = new PersonDemo();
Person p = new Student();
pd.method(p);
}
}
//接口作为方法的形式参数
interface Love {
public abstract void love();
}
class LoveDemo {
public void method(Love l) { //l; l = new Teacher(); Love l = new Teacher(); 多态
l.love();
}
}
//定义具体类实现接口
class Teacher implements Love {
public void love() {
System.out.println("老师爱学生,爱Java");
}
}
class TeacherTest {
public static void main(String[] args) {
//需求:我要测试LoveDemo类中的love()方法
LoveDemo ld = new LoveDemo();
Love l = new Teacher();
ld.method(l);
}
}
引用类型作为返回值
类:返回的是该类的对象
抽象类:返回的是该抽象类的子类对象
接口:返回的是该接口的实现类的对象
//类最为返回值
class Student {
public void study() {
System.out.println("Good Good Study,Day Day Up");
}
}
class StudentDemo {
public Student getStudent() {
//Student s = new Student();
//Student ss = s;
//Student s = new Student();
//return s;
return new Student();
}
}
class StudentTest2 {
public static void main(String[] args) {
//需求:我要使用Student类中的study()方法
//但是,这一次我的要求是,不要直接创建Student的对象
//让你使用StudentDemo帮你创建对象
StudentDemo sd = new StudentDemo();
Student s = sd.getStudent(); //new Student(); Student s = new Student();
s.study();
}
}
//抽象类作为返回值
abstract class Person {
public abstract void study();
}
class PersonDemo {
public Person getPerson() {
//Person p = new Student();
//return p;
return new Student();
}
}
class Student extends Person {
public void study() {
System.out.println("Good Good Study,Day Day Up");
}
}
class PersonTest2 {
public static void main(String[] args) {
//需求:我要测试Person类中的study()方法
PersonDemo pd = new PersonDemo();
Person p = pd.getPerson(); //new Student(); Person p = new Student(); 多态
p.study();
}
}
//接口作为返回值
interface Love {
public abstract void love();
}
class LoveDemo {
public Love getLove() {
//Love l = new Teacher();
//return l;
return new Teacher();
}
}
//定义具体类实现接口
class Teacher implements Love {
public void love() {
System.out.println("老师爱学生,爱Java");
}
}
class TeacherTest2 {
public static void main(String[] args) {
//如何测试呢?
LoveDemo ld = new LoveDemo();
Love l = ld.getLove(); //new Teacher(); Love l = new Teacher(); 多态
l.love();
}
}
链式编程
每次调用完毕后返回的是一个对象(只有对象才能继续调方法)
class Student {
public void study() {
System.out.println("Good Good Study,Day Day Up");
}
}
class StudentDemo {
public Student getStudent() {
return new Student();
}
}
class StudentTest3 {
public static void main(String[] args) {
//如何调用的呢?
StudentDemo sd = new StudentDemo();
//Student s = sd.getStudent();
//s.study();
//相当于下边的
sd.getStudent().study();
}
}
包
其实就是文件夹
作用
把相同的类名放到不同的包中
对类进行分类管理
举例:
学生:增加,删除,修改,查询
老师:增加,删除,修改,查询
...
方案1:按照功能分
cn.itcast.add
AddStudent
AddTeacher
cn.itcast.delete
DeleteStudent
DeleteTeacher
cn.itcast.update
UpdateStudent
UpdateTeacher
cn.itcast.find
FindStudent
FindTeacher
方案2:按照模块分
cn.itcast.teacher
AddTeacher
DeleteTeacher
UpdateTeacher
FindTeacher
cn.itcast.student
AddStudent
DeleteStudent
UpdateStudent
FindStudent
包的定义
package 包名;
多级包用.分开即可
注意事项:
package语句必须是程序的第一条可执行的代码
package语句在一个java文件中只能有一个
如果没有package,默认表示无包名
带包的编译和运行:
手动式
编写一个带包的java文件
通过javac命令编译该java文件
手动创建包名
把b步骤的class文件放到c步骤的最底层包
回到和包根目录在同一目录的地方,然后运行
带包运行
自动式
编写一个带包的java文件
javac编译的时候带上-d即可
javac -d . HelloWorld.java
回到和包根目录在同一目录的地方,然后运行
带包运行
导包
格式:import 包名;
这种方式导入是到类的名称,注意:我们用谁就导谁
例:import cn.itcast.Demo //Demo为类名
package,import,class的顺序关系
package > import > class
Package:只能有一个
import:可以有多个
class:可以有多个,以后建议是一个
权限修饰符的访问
本类 同一个包下(子类和无关类) 不同包下(子类) 不同包下(无关类)
private Y
默认 Y Y
protected Y Y Y
public Y Y Y Y