JAVA基础
注释
1).单行注释 //
2).多行注释
/*
*/
3).文档注释 (在生成文档时会保留下)
/**
*/
第一个java文件
public class HelloWorld{ public static void main(String[] args){ System.out.print("hello world"); } }
|
输出语句
System.out.print
System.out.println
System.out.printf
区别:
1、print 将它的参数显示在命令窗口,并将输出光标定位在所显示的最后一个字符之后。
System.out.print(参数) 参数不能为空.必须有
2、println 将它的参数显示在命令窗口,并在结尾加上换行符,将输出光标定位在下一行的开始。
System.out.println() 可以不写参数
3、printf 是格式化输出的形式(即可以控制输出的格式)。
%d的意思是一个int值的占位符
%f为一个double 或float值的占位符
%s为一个string值的占位符
%.2f:输出两位小数点
%.3f:输出三位小数点
例:
public class a {
public static void main(String args[]) {
int i=9;
double j=10.4;
System.out.print("i,j的值分别为:"+i+","+j);
System.out.print("\n");
System.out.println("i,j的值分别为:"+i+","+j);
System.out.printf("i的值为%d,j的值为%f",i,j);
System.out.println();
System.out.printf("i的值为%d,j的值为%.2f",i,j);
}
}
|
变量
1)定义:
计算机内存中的一块存储空间,是存储数据的基本单元
2)声明:
数据类型 变量名;
赋值:
变量名=值;
使用:
System.out.print(变量名);
可以声明时一起赋值
3)标识符
由字母,货币符号(英文状态下的),下划线(-),数字组成
不能以数字开头
不能与关键字、保留字重名
不能与字面常量重名(true false null)
命名方法:
a.帕斯卡法(pascal)每个单词首字母大写
b.驼峰命名法(camel)首单词首字母小写,后续单词首字母大写
数据类型
java中的变量有严格的数据类型区分(强类型语言)
java中任意一个值都有其对应的类型的变量。
基本数据类型共8种
整数
整数默认为int(运算时) 但在具体赋值时会窄化成具体类型
如果为long类型(超过int的极限时),需要在值的后面加“L”(不加就会转换成int)
小数(浮点型)
浮点型数值采用科学计数法表示
double为浮点数的默认类型,要切换成float类型时,要在后面的值加“f”
布尔型
可直接赋值true/false
也可以赋值一个结果为true/false的表达式
boolean不能参与算数运算
字符
ascii码:
0:48 A:65 a:97
赋值方式:
转义字符:
字符串
例题
类型转换
1.自动类型转换
两种类型相互兼容
目标类型大于原类型
short->int
2.强制类型转换
两种类型相互兼容
目标类型小于原类型
int->short
强制转换规则:
自动类型提升
运算符
算数运算符
a=10 b=8
System.out.print("a+b="+a+b);
|
此时会输出108 因为字符串拼接会转换成字符串 所以”a+b=”+a拼接了(10)
+(拼接符)b(8)成字符串拼接在一起(108)
要想输出正确结果,就要加括号,改变其运算顺序
System.out.print("a+b="+(a+b));
|
这样就是18
同理:
System.out.print("a+b="+a-b);
|
报错 因为字符串不能与整数相减
要改成
System.out.print("a+b="+(a-b));
|
特殊:
除数不能为0
5/0 报错->by zero
5.0/0 报错->infinity(无限大)
-5.0/0 报错->-infinity(无限小)
0.0/0 ——>NaN(not a number)
++–
++在前,先自增再使用自增后的结果
++在后,先使用自增前的结果再自增
–同理
赋值运算符
赋值运算符:等号右边赋值给等号左边
例:
因为+是一个二元运算符 会将s1+s2的结果转换为int 此时要强制转换才行
而+=是一个复合赋值运算符 是一元运算符 会将结果窄化,窄化为short 所以不影响
其他运算符
关系运算符
两个操作数进行比较
比较结果都是布尔值
逻辑运算符
两个boolean类型的操作数或表达式进行逻辑比较
短路与:
正常 此时b=11
短路 此时b=10 因为在判断a>9为false后 因为后面式&& 程序认为不用判断后续程序即可得到结果false,所以没有执行b++==10 ,所以b=10
但若是前面为a>b 则仍要执行后续代码
同理有短路或
三元运算符
将判断后的结果赋值给变量
运算符的优先级
- 括号优先
- 算数>关系>赋值
- */%>+-
- !>&&>||
控制台输入
理解:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); double width = scanner.nextDouble(); double height = scanner.nextDouble(); double area = width * height; double perimeter = (width + height) * 2; System.out.println("The area is " + area); System.out.println("The perimeter is " + perimeter); scanner.close(); } }
|
import java.util.Scanner; public class TestS{ public static void main (String[] args){ Scanner input = new Scanner(System.in); String name = input.next(); int age = input.nextInt(); char gender=input.next().charAt(0); System.out.println(”姓名: “+name); System.out.println(”年龄: “+age); System.out.println(”性别: “+gender); } }
|
选择结构
简单if
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner.scanner=new Scanner(System.in); System.out.println("成绩:"); int a=scanner.nextInt(); if(a>=90){ System.out.println("周末放假"); } } }
|
if-else
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); System.out.println("成绩:"); int a=scanner.nextInt(); if(a>=90){ System.out.println("周末放假"); }eles{ System.out.println("滚去学习") } } }
|
多重if
import java.util.Scannr; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); System.out.println(钱:); int a=scanner.nextInt(); if (a>=500){ System.out.println("法拉利"); }else if(a>=100){ System.out.println("保时捷"); }else if(a>=50){ System.out.println("奔驰"); }else if(a>=10){ System.out.println("大众"); }else{ System.out.println("五菱宏光,都有能买的车了,你还要什么自行车"); } } }
|
从大到小排或从小到大排
要连续区间
嵌套if
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); System.out.println("预赛成绩"); int a=scanner.nextInt(); if(a<=10){ System.out.println("性别"); char gender=scanner.next().charAt(0); if(gander=='男'){ System.out.println("男子决赛"); }else{ System.out.println("女子决赛"); } }else{ System.out.println("很遗憾"); } } }
|
分支结构
只要是Int即可判断
byte short char 都可以转换成Int
string本质上是int(hashCode)
long不行Long不能转成32位的int
case的值不能相同
当执行成功一个case会继续向下执行直到遇到break
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); System.out.println("银行简写"); String bank=scanner.next(); switch(bank){ case"icbc": case"ICBC": System.out.println("工商银行"); break; case"bc": System.out.println("中国银行"); break; case"cbc": System.out.println("建设银行"); break; default System.out.println("输入有误"); break; } } }
|
使用toLowerCase()可以把大写转成小写
switch(bank.toLowerCase())
循环结构
概念:通过某个条件,重复执行一段逻辑代码
while循环
public class Main{ public static void main(String[] args){ int i=1; while(i<=100){ System.out.println("第"+i+"次输出HelloWorld"); i++ } } }
|
while是先判断后执行
public class Main{ public static void main(String[] args){ int sum=0,odd=0,even=0; int i=1; while(i<=100){ sum=sum+i; if(i%2==1){ odd+=i; }else{ even+=i; } i++; } System.out.println("sum="+sum); System.out.println("odd="+odd); System.out.println("even="+even); } }
|
do-whlie
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); int score; do{ System.out.println("第一阶段成绩为:"); score=scanner.nextInt(); }while(score<60); System.out.println("本阶段考试成功"); } }
|
public class Main{ public static void main(String[] args){ int i=1; do{ System.out.println("第"+i+"次输出HelloWorld"); i++ } while(i<=100); System.out.println("结束"); } }
|
for循环
for循环是从while循环演变过来的,所以他们之间可以互相转换
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); System,out,println("输入一个数"); int mul=1; int n=scanner.nextInt(); for(i=1;i<=n;i++){ mul=mul*i; } System.out.println(mul); } }
|
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); int sum=0; for(i=1;i<=5;i++){ System.out.println("第"+i+"名同学分数:"); int score =scanner.nextInt(); sum+=score; } System.out.println("平均分为"+sum/5); } }
|
流程控制
break
public class Main{ public static void main(String[] args){ int i=1; for(;i<=10;i++){ System.out.println("第"+i+"个数字"); if(i==5){ break; } } System.out.println("完成,此时i为:"+i); } }
|
Break后会直接跳过后续代码,且for中不会I++
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); int sum=0; int count=0; for(i=1;i<=5;i++){ System.out.println("第"+i+"名同学分数:"); int score =scanner.nextInt(); if(score<0){ System.out.println("输入异常,终止输入"); break; } sum+=score; count++; } if(count==0){ System.out.println("本次录入无效"); }else{ System.out.println("当前人数为:"+count+"平均分为"+sum/count); } } }
|
continue
public class Main{ public static void main(String[] args){ int i=1; for(;i<=10;i++){ if(i==5){ continue; } System.out.println("第"+i+"个数字"); } System.out.println("完成,此时i为:"+i); } }
|
会跳过后续代码,但会继续执行循环,执行i++
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); int sum=0; for(i=1;i<=5;i++){ System.out.println("第"+i+"名同学分数:"); int score =scanner.nextInt(); if(score<0){ System.out.println("输入异常,重新输入"); i--; continue; } sum+=score; } System.out.println("平均分为"+sum/5); } }
|
嵌套循环
概念:在一个完整的循环结构中,嵌套另一个完整的循环
外层循环循环一次,内存循环循环一轮
public class Main{ public static void main(String[] args){ for(int i=1;i<=3;i++){ for(int j=1;j<=5;j++){ System.out.print("*"); } System.out.println(); } } }
|
外层循环控制行数,内层循环控制列数
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner=new Scanner(System.in); for(int i;i<=3;i++){ int sum=0; for(int j;j<=5;j++){ System.out.println("第"+i+"个班,第"+j+"个同学的成绩是:"); sum+=scanner.nextInt(); } System.out.println("第"+i+"个班的平均分是:"+sum/5); } } }
|
public class Main{ public static void main(String[] args){ for(int i;i<=5;i++){ for(int j;j<=i,j++){ System.out.print("*"); } System.out.println(); } for(int i;i<=5;i++){ for(int j=1;j<=5-i;j++){ System.out.print(""); } for(int j;j<=i,j++){ System.out.print("*"); } System.out.println(); } for(int i;i<=5;i++){ for(int j=1;j<=5-i;j++){ System.out.print(""); } for(int j;j<=2*i-1,j++){ System.out.print("*"); } System.out.println(); } for(int i;i<=5;i++){ for(int j=1;j<=5-i;j++){ System.out.print(""); } for(int j;j<=2*i-1,j++){ System.out.print("*"); } System.out.println(); } for(int i;i<=5;i++){ for(int j=1;j<=i;j++){ System.out.print(""); } for(int j;j<=2*(5-i)-1,j++){ System.out.print("*"); } System.out.println(); } } }
|
方法与函数
实际上方法就是函数,只是在面向对象编程中,将函数称为方法
语法
在java中不允许在方法中定义方法
所以只有2和4能定义方法
main方法是程序的入口,一开始程序就会执行,而普通方法必须在main方法中进行调用才能执行
public class Main{ public static void main(String[] args){ System.out.println("窗前明月光,"); printSign(); System.out.println("疑是地上霜。"); printSign(); System.out.println("举头望明月,"); printSign(); System.out.println("低头思故乡。"); printSign(); } public static void printSign(){ System.out.println("---------"); } }
|
在需要执行代码的地方,通过方法名称进行调用方法
调用方法时,会优先执行方法内部代码,结束后,返回到方法调用处,继续向下执行
参数
形参与实参
public class Main{ public static void main(String[] args){ System.out.println("窗前明月光,"); printSign(10,#); System.out.println("疑是地上霜。"); printSign(10,$); System.out.println("举头望明月,"); printSign(10,%); System.out.println("低头思故乡。"); printSign(10,^); } public static void printSign(int count,char sign){ for (int i=1;i<=count;i++){ System.out.println(sign); } System.out.println(); } }
|
返回值
参数是调用者给方法的输入,返回值是方法给调用者的反馈
public class Main{ public static void main(String[] args){ int a; int b; int c = add(a,b); System.out.println(c); } public static int add (int a,int b){ return a+b; } }
|
返回值只能有一个,也就是说返回过来的值只能有一个
即:不能有:
public static int add (int a,int b){ return a+b; return a-b; }
|
但是这种可以:
public class Main{ public static void main(String[] args){ int a; int b; if(num%2==0){ return "偶数"; }else{ return "奇数"; } } }
|
同时这种不行:
public class Main{ public static void main(String[] args){ int num; if(num%2==0){ return "偶数"; }else if(num%==1){ return "奇数"; } } }
|
因为编译器认为你else if后面可能还有if 而if后没有返回值 报错,所以至少要在后面再加一个返回值
如果此时是break,是指跳到for循环外,继续执行后续代码,这里是到}外
而return,在无返回值时可写可不写,写了就表示结束方法,这里时回到{
调用与递归
多级调用:
public class Main{ public static void main(String[] args){ m1(); } public static void m1(){ System.out.println("m1-start"); m2(); System.out.println("m1-end"); } public static void m2(){ System.out.println("m2-start"); System.out.println("m2-end"); } }
|
先执行m1,再执行m2,然后执行m1后续
无穷递归
public class Main{ public static void main(String[] args){ m1(); } public static void m1(){ System.out.println("m1-start"); m1(); System.out.println("m1-end"); } }
|
此时会无限调用m1,导致方法栈溢出,报错
递归
递归阶乘
public class Main{ public static void main(String[] args){ int num = f(5); System.out.println(num); } public static int f(int n){ return n==1?1:n*f(n-1); } }
|
if同理
递归:斐波那契数列
后面的数是前两个数之和:1 1 2 3 5 8 13 21 34 55
public class Main{ public static void main(String[] args){ int num=getRabit(20); System.out,println(num); } public static int getRabit(int n){ return n==1||n==2?1:getRabit(n-1)+getRabit(n-2); } }
|
数组
概念
一组连续的存储空间,存储多个相同数值类型的值
创建:
先声明 再分配空间: 数据类型[] 数组名; 数组名=new 数据类型[长度]; int[] a; a=new int[5] 声明并分配空间: 数据类型[] 数组名=new 数据类型[长度]; int[] a= new int[5];
声明并赋值1: 数据类型[] 数组名=new 数据类型[]{1,2,3}; int[] a=new int[]{1,2,3};
声明并赋值2: 数据类型[] 数组名={1,2,3}; int[] a={1,2,3};
|
遍历
遍历:从头至尾,逐一对数组的每个元素进行访问
public class Main{ public static void main(String[] args){ int[] nums={1,2,3,4,5,6}; for(int i=0;i<nums.length;i++) System.out.println(nums[i]); } }
|
默认值:
默认值会根据数据类型的不同而改变
int–>0
double–>0.0
boolean–>false
char–>-\u000
其他(引用类型)–>null
public class Main{ public static void main(String[] args){ int[] nums={8,7,9,3,5}; int sum=0; for(int i=0;i<nums.length;i++) sum += nums[i]; System.out.println(sum/nums.length); } }
|
import java.util.Scanner public class Main{ public static void main(String[] args){ int[] nums={8,7,9,3,5,6,10}; Scanner scanner=new Scanner(System.in); int num = input.nextInt; boolean flag=false for(int i=0;i<nums.length;i++) if(nums[i]==num);{ System.out.println(i); flag=true; break; } } if(flag=false){ System.out.println(666); } } }
|
扩容
length属性是只读权限 不能赋值
所以扩容就是创建一个新数组然后把旧数组的值重新传进来
public class Main{ public static void main(String[] args){ int[] nums={11,22,33,44,55}; int[] newNums=new int[nums.length*2]; for(int i=0;i<nums.length;i++) newNums[i]=nums[i]; } nums=newNums; System.out.println(Arrays.toString(nums)) } }
|
nums=newNums;
因为数组是引用类型,所以在声明数组时会在堆中开辟一段空间 将nums的地址指向这个堆空间
而将nums=newNums;此时是进行栈操作,将nums的地址指向newNums的堆空间 进而实现数组的拓展
复制的方法:
public class Main{ public static void main(String[] args){ nums=Array.copyof(nums,nums.length*2); System.out.println(Arrays.toString(nums)) } }
|
数组型参数与返回值
public class Main{ public static void main(String[] args){ int[] nums={1,2,3,4,5,6}; add(nums); System.out.println(Arrays.toString(nums)) } public static void add(int[] nums){ for(int i=0;i<nums.length;i++){ nums[i]+=1; } } }
|
因为这里当数组作为一个参数时,方法会获取他堆地址进行操作
public class Main{ public static void main(String[] args){ int[] nums={1,2,3,4,5,6}; expand(nums); } public static void expand(int[] nums){ nums=Arrays.copyof(nums,nums.Lenth*2); System.out.println(Array.toString(nums)); } public static void add(int[] nums){ for(int i=0;i<nums.length;i++){ nums[i]+=1; } } }
public class Main{ public static void main(String[] args){ int[] nums={1,2,3,4,5,6}; expand(nums); System.out.println(Array.toString(nums)); } public static void expand(int[] nums){ nums=Arrays.copyof(nums,nums.Lenth*2); } public static void add(int[] nums){ for(int i=0;i<nums.length;i++){ nums[i]+=1; } } }
public class Main{ public static void main(String[] args){ int[] nums={1,2,3,4,5,6}; nums=expand(nums); System.out.println(Array.toString(nums)); } public static int[] expand(int[] nums){ nums=Arrays.copyof(nums,nums.Lenth*2); return nums; } public static void add(int[] nums){ for(int i=0;i<nums.length;i++){ nums[i]+=1; } } }
|
可变长参数
public class Main{ public static void main(String[] args){ add(1,2,3,4); } public static void add(int...nums){ int sum=0; for(int i=0;i<nums.length;i++){ nums[i]+=1; } System.out.println(sum); } }
|
可变长参数其实就是未封装的数组
但可变长参数只能在最后一个形参处调用
排序
排序的目的是为了方便数据的查找
有10种排序方法
冒泡排序 选择排序 插入排序 n*n
快速排序 堆排序 希尔排序 归并排序 n*log2n
桶排序 计数排序 计数排序
public class Main{ public static void main(String[] args){ int[] nums = {3,5,9,56,84,24,12,8}; bubbleSort(nums); System.out.println(Array.toString(nums)); } public static void bubbleSort(int[] nums){ for(int i=0;i<nums.length-1;i++){ for(int j=0;j<nums.length-1-i;j++){ if(nums[j]<nums[j+1]){ int temp = nums[j]; nums[j]= nums[j+1]; nums[j+1]=temp; } } } } }
public class Main{ public static void main(String[] args){ int[] nums = {3,5,9,56,84,24,12,8}; Arrays.sort(nums); System.out.println(Array.toString(nums)); } }
public class Main{ public static void main(String[] args){ int[] nums = {1,2,4,3,2,4,1,3,4,2}; int[] counts=new int[4]; for(int i=0;i<nums.length;i++){ counts[nums[i]-1]++; } int[] newNums=new int[nums.length]; int index=0; for(int i=0;i<counts.length;i++){ for(int j=0;j<counts[i];j++){ newNums[index++]=i+1; } } nums=newNums; System.out.println(Arrays.toString(nums)); } }
|
查找
public class Main{ public static void main(String[] args){ int[] nums = {1,6,2,35,48,5}; int num = 5; int index=getNum(nums,num); System.out.println(index); Array.sort(nums); int index=binarySearch(nums,num); System.out.println(index); } public static int getNum(int[] nums,int num){ for(int i=0;i<nums.length;i++){ if(nums[i]==num){ return i; } } return -1; } public static int binarySearch(int[] nums,int num){ int begin=0; int end=nums.length-1; int mid; while(begin<=end){ mid=(begin+end)/2 if(nums[mid]==num){ return mid; }else if(nums[mid]==num){ }else{ begin=mid+1; } } return -1; } }
|
二维数组
概念:
赋值:
内存分配
访问:
声明:
高维长度是必要的 低维长度可要可不要
public class Main{ public static void main(String[] args){ int[][]nums={{1,2,3},{4,5,6},{7,8,9}}; for(int i=0;i<nums,length;i++){ for(int j=0;j<nums[i].length;j++){ System.out.println(nums[i][j]+" "); } System.out.println(); } } }
|
public class Main{ public static void main(String[] args){ int[][]nums=new int[10][]; for(int i=0;i<nums.length;i++){ nums[i]=new int[i+1]; nums[i][0]=1; nums[i][i]=1; for(int j=1;j<nums[i].length-1;j++){ nums[i][j]=nums[i-1][j-1]+nums[i-1][j]; } } for(int i=0;i<nums,length;i++){ for(int j=0;j<nums[i].length;j++){ System.out.println(nums[i][j]+" "); } System.out.println(); } } }
|
面向对象
对象
类
public class Dog{ String brand; String name; int age; String color; public void eat(){ System.out.println(name+"eating"); } public void sleep(){ System.out.println(name+"sleeping"); } }
public class Main{ public static void main(String[] args){ Dog dog=new Dog(); dog.brand="1"; dog.name="2"; dog.age="3"; dog.color="4"; dog.eat(); dog.sleep(); } }
|
类(类型)是一种模板(1个) 根据类可以创建出多个对象(实例)
方法与属性
属性
属性是有默认值的 所有在类的定义中可以不赋值 直接调用
就近原则:谁离我近 谁对我起作用(作 用域更小的起作用)
方法
public class Student{ String name; int age; String sex; int score; public void sayHi(){ System.out.println(name+"---"+age+"---"+sex+"---"+score); } }
public class Main{ public static void main(String[] args){ Student s1=new Student(); s1.name="2"; s1.age="3"; s1.sex="4"; s1.score="5"; s1.sayHi(); Student s2=new Student(); s2.name="a"; s2.age="b"; s2.sex="c"; s2.score="d"; s2.sayHi(); } }
|
方法重载
有些情况下,对象的同一种行为可能存在多种实现过程(吃饭与吃药 都是吃 但过程存在差异)
这样直接写的话会出现一个问题就是:方法名太多。而重载存在的意义就是解决方法名的问题 他允许一个方法名执行多个方法 根据传来的参数不同 执行不同的方法
注:参数要不同 与返回值类型无关 与形参名字无关
构造方法
构造方法也可以重载,遵循重载规则
public class Student{ String name; int age; String sex; int score; public Student(String n,int a,String s,int sc){ name=n; age=a; sex=s; score=sc; } public Student(){ } public void sayHi(){ System.out.println(name+"---"+age+"---"+sex+"---"+score); } }
public class Main{ public static void main(String[] args){ Student s1=new Student("2",3,"4",5); s1.sayHi(); Student s2=new Student(); s2.name="a"; s2.age="b"; s2.sex="c"; s2.score="d"; s2.sayHi(); } }
|
this关键字
用法1:
用法2:
当两个构造方法当中,包含多条冗余代码时
public Student(String name,int age,String sex){ this.name=name; this.age=age; this.sex=sex; }
public Student(String name,int age,String sex,int score){ this(name,age,sex); this.score=score; }
|
在对象创建时 一旦分配空间 就已经存在this了 指向这个空间
封装
本来这样是直接给age赋值 可能无意或恶意输入错误值
所以用set get 方法
这样将接受和赋值分开 可以让是否赋值的主动权在我们手中(可以判断)
public class character { public static void main(String[] args) { Student s1=new Student(); s1.setAge(22000); System.out.println(s1.getAge()); } } public class Student{ String name; private int age; String gender; double score;
public void setAge{ if(age>=0&&age<=120) { this.age = age; }else{ this.age=18; } } public void getAge{ return age; } }
|
封装的好处:
继承
概念
程序中的继承,是类与类之间特征和行为的一种赠与或获得
两个类之间的继承关系,必须满足”is a”的关系
父类的选择:
一个对象其实是有很多的父类
public class Pet{ String name; int health; int love;
public void eat(){ System.out.println(name+" is eating"); } public void show(){ System.out.println(name+"-"+health+"-"+love); }
public String getName(){ return name; } public void setName(String name){ this.name=name; } public int getHealth(){ return health; } public void setHealth(int health){ this.health=health; } public int getLove(){ return love; } public void setLove(int love){ this.love=love; } }
public class Dog extends Pet{ String strain; public void catchDisk(){ System.out.println("在玩飞盘"); }
public String getStrain(){ return strain; } public void setStrain(String strain){ this.strain=strain; } }
public class Penguin extends Pet{ String gender; public void swim(){ System.out.println("在游泳"); } public String getGender(){ return gender; } public void setGender(String gender){ this.gender=gender; } }
public class exercise { public static void main(String[] args) { Dog d = new Dog(); d.name="汪汪"; System.out.println(d.name); d.show(); Penguin p = new Penguin(); p.name="QQ"; System.out.println(p.name); p.show(); } }
|
在一组相同或类似的类中,抽取出共性的特征和行为,定义在父类中,实现重用
子类通过extends来继承
特点
单根性:一个类只能有一个直接的父类
传递性:类之间可以多级继承,属性和方法逐级叠加
public class Person{ String name; int age;
public void display(){ System.out.println(name +"-"+ age); }
public String getName(){ return name; } public int getAge(){ return age; } public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } }
public class SE extends Person{ public void code(){ System.out.println(name+"coding"); } }
public class Student extends SE{ int score; public void dowork(){ System.out.println(name +"studying"); } }
public static void main(String[] args) { Student s=new Student; s.name="Ozero"; s.age=19; s.score =150; s.dowork(); s.show(); s.code(); }
|
可以通过接口与内部类来实现多继承
属性的继承
父类的所以属性都可以被继承
但是父类的私有属性不能被访问
当子类和父类有同名属性的时候可以通过super关键字区分
sub继承sup
不加super–>当前对象的属性
加super–>父类被继承道子类的属性
public class Sup { private int a=1; public int b=2; }
public class Sub extends Sup{ public char c='c'; public int b=3; public class show(){ System.out.println(super.b) } }
public static void main(String[] args) { Sub sub=new Sub(); sub.show(); }
|
默认是default
方法的重写与覆盖
如果父类提供的方法无法满足子类需求时,可在子类中定义和父类相同的方法进行重写(Override)
public class Pet{ String name; int health; int love;
public void eat(){ System.out.println(name+" is eating"); } public void show(){ System.out.println(name+"-"+health+"-"+love); }
public String getName(){ return name; } public void setName(String name){ this.name=name; } public int getHealth(){ return health; } public void setHealth(int health){ this.health=health; } public int getLove(){ return love; } public void setLove(int love){ this.love=love; } }
public class Dog extends Pet{ String strain; public void catchDisk(){ System.out.println("在玩飞盘"); }
public void show(){ super.show(); System.out.println(strain); }
public String getStrain(){ return strain; } public void setStrain(String strain){ this.strain=strain; } }
public class exercise { public static void main(String[] args) { Dog d = new Dog(); d.name="汪汪"; d.health=10; d.love=5; d.strain="修狗" d.show(); } }
|
当然 也可以不用 super.show(); 直接完全重写也行 但这时是默认default 所以可以直接访问
System.out.println(name+"-"+health+"-"+love+"-"+strain);
|
但如果这时是private呢
肯定不能这样访问
System.out.println(getName()+"-"+getHealth()+"-"+getLove()+"-"+strain);
|
他把门关了,我们调用这个窗户就行
当然 这里也要改
public class exercise { public static void main(String[] args) { Dog d = new Dog(); d.setName(汪汪); d.setHealth(10); d.setLove(5); d.strain="修狗" d.show(); } }
|
如果父类里strain也是private 也需要setStrain()
方法重写的时候 访问权限可以放大 不能减小
返回值类型可以和父类一样,也可以是父类返回值类型的子类
方法名要一样
参数列表也必须相同
父类的私有的东西是不能被重写的
继承中的对象创建
在具有继承关系的对象创建中,构建子类对象会先调用父类构造
由父类的共性类容,叠加子类的独有内容,组合成完整的子类对象
只会调用父类的构造方法 而不会去创建父类
public class exercise { public static void main(String[] args) { C c=new C(7,8,9); System.out.println(c.a+"--"+c.b+"--"+c.c); } } class A{ int a=4; public A(int a){ this.a=a; System.out.println("A(int)"); } } class B extends A{ int b=3; public B(int b,int a){ super(a); this.b=b; System.out.println("B(int,int)"); } } class C extends B{ int c=5; public C(int c,int b,int a){ super(a,b); this.c=c; System.out.println("C(int,int,int)"); } }
|
super() 表示调用父类无参构造
super(实参) 表示调用父类带参构造
多态
概念
多态=继承+重写
多态表现形式:调用父类的方法,执行子类的方法
这里是向上转型
多态的应用
1.使用父类作为方法形参实现多态,使方法参数的类型更为宽泛
代码与前面的相结合一下 这里只写重点代码了
public class character { public void feed(Pet){ pet.eat(); }
public static void main(String[] args) { character m = new character(); m.feed(new Dog()); } }
|
2.使用父类作为方法返回值实现多态,使方法可以返回不同子类对象
public class character { public void feed(pet){ pet.eat(); }
public Pet getPet(String type){ if(type.equals("cat")){ return new Dog(); }else { return new Penguin(); } }
public static void main(String[] args) { character m = new character(); Pet pet = m.getPet("Dog"); m.feed(new Dog()); } }
|
向下转型(拆箱)
一个对象在调用方法的时候,能调用到哪些方法取决于对象的类型
执行方法的时候,执行哪个方法取决于实际类型
public class character { public void feed(pet){ pet.eat(); }
public void play(Pet pet){ Dog dog=(Dog)pet; dog.catchDisk(); }
public Pet getPet(String type){ if(type.equals("cat")){ return new Dog(); }else { return new Penguin(); } }
public static void main(String[] args) { character m = new character(); Pet pet = m.getPet("Dog"); m.feed(new Dog()); m.play(Pet); } }
|
Dog dog=(Dog)pet;
将父类引用中的子类对象,强制转回子类本身类型,称为向下转型
只要转回子类真实类型,才可调用子类独有的属性和方法
向下转型时,如果父类引用中的子类对象类型和目标类型不匹配,则会发生类型转换异常(classCastException)
解决:
判断传来的是什么
instanceof关键字
public class character { public void feed(pet){ pet.eat(); }
public void play(Pet pet){ if(pet instanceof Dog){ Dog dog=(Dog)pet; dog.catchDisk(); }else { Penguin p =(Penguin) pet; p.swim(); } }
public Pet getPet(String type){ if(type.equals("cat")){ return new Dog(); }else { return new Penguin(); } }
public static void main(String[] args) { character m = new character(); Pet pet = m.getPet("Dog"); m.feed(new Dog()); m.play(Pet); } }
|
向下转型前,应先判断引用中对象真实类型,保证类型转换的正确性
抽象
abstract
介绍
abstract 抽象
这是上面写的Pet类 并加上了abstract
public abstract class Pet{ String name; int health; int love;
public void eat(){ System.out.println(name+" is eating"); } public void show(){ System.out.println(name+"-"+health+"-"+love); }
public String getName(){ return name; } public void setName(String name){ this.name=name; } public int getHealth(){ return health; } public void setHealth(int health){ this.health=health; } public int getLove(){ return love; } public void setLove(int love){ this.love=love; } }
|
因为这个Pet是一个抽象出来的类 所以它不能被实例化
Pet pet=new Pet(); //这样不行 只能new Dog()这种
|
作用
那抽象类的作用是什么呢
1.可被子类继承
2.可声明为引用
抽象方法
在抽象类中 只用声明这个方法就行 具体实现在子类中(必须 若这个子类不是抽象的化 抽象的化就会让子类的子类来实现)
public abstract class Pet{ String name; int health; int love;
public abstract void eat(); public void show(){ System.out.println(name+"-"+health+"-"+love); }
public String getName(){ return name; } public void setName(String name){ this.name=name; } public int getHealth(){ return health; } public void setHealth(int health){ this.health=health; } public int getLove(){ return love; } public void setLove(int love){ this.love=love; } }
|
抽象方法必须放在抽象类中(或接口中)
static
介绍
静态
实例属性:
public class Myclass { int a; }
public class Text { public static void main(String[] args) { Myclass mc1 = new Myclass(); mc1.a = 10; Myclass mc2 = new Myclass(); mc2.a = 20; System.out.println(mc1.a+"---"+mc2.a); } }
|
静态属性:
public class Myclass { static int a; }
public class Text { public static void main(String[] args) { Myclass mc1 = new Myclass(); mc1.a = 100; Myclass mc2 = new Myclass(); mc2.a = 200; System.out.println(mc1.a+"---"+mc2.a); } }
|
注意 这里用mc1.b
来调用实际上警告了的(java中) 因为b实际上是在类中 该用Myclass.b
来调用
这里可以通过静态变量来统计类对象被创建了多少词
静态方法
public class Myclass { int a;
public static void m1() { System.out.println("M1"); m2(); new Myclass().m3(); }
public static void m2() { System.out.println("M2"); }
public void m3() { System.out.println("M2"); } }
public class Text { public static void main(String[] args) {
Myclass.m1(); } }
|
在静态方法中不能用this super
public class Myclass { int a;
public static void m1() { System.out.println("M1"); m2(); }
public static void m2() { System.out.println("M2"); }
public void m3() { System.out.println("M2"); } }
public class Text { public static void main(String[] args) {
Myclass mc = new SubClass(); mc.m1();
SubClass.m1(); } }
class SubClass extends Myclass{ public static void m1() { System.out.println("sub-m1"); }
}
|
类加载
反射时会主动加载
静态代码块
静态代码块会优先于类 构造方法之类的先执行 一般用于初始化
public class Myclass { int a=888;
static { System.out.println(a); System.out.println("static block"); }
}
public class Text { public static void main(String[] args) { new Myclass(); } }
|
final
介绍
final修饰类:此类不能被继承
final修饰方法:此方法不能被覆盖
final修饰变量:此变量不能被改变(常量)
普通常量:
静态常量:
对象常量:
常量是一个对象
接口
语法
接口相当于特殊的抽象类,定义方法、组成部分与抽象类类似
interface
public interface MyInterface{ public static final String FIELD="value"; public abstract void m1(); void m2(); double VERSION=1.0; }
|
jdk8以前:
接口中只能写:
1.公开静态常量
2.公开抽象方法
接口的使用:
接口相当于一个抽象父类
public interface MyInterface{ public static final String FIELD="value"; public abstract void m1(); void m2(); double VERSION=1.0; }
public class SubTest implements MyInterface{ public void m1(){ System.out.println("sub-M1"); } }
public class Test{ public static void main(String[] args){ SubTest sub = new SubTest(); sub.m1();
MyInterface sub = new SubTest(); sub.m1(); } }
|
与抽象类的异同:
介绍
public interface ICode{ void code(); }
public interface IPlay{ void play(); }
public class Student implements IPlay,ICode{
public void code(){ System.out.println("会编码"); }
public void play(){ System.out.println("弹钢琴"); } }
public static void main(String[] args){ Student s = new Student(); s.code(); s.play(); }
|
接口的规范
- 任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类
- 实现接口中的抽象方法时,访问修饰符必须时public
接口引用
同父类一样,接口也可以声明为引用,并指向实现类对象
注:
- 仅可调用接口中声明的方法,不可调用实现类中独有的方法
- 可强回转实现类本身类型,进行独有方法调用
接口的多态
不同引用类型,仅可调用自身类型中所什么的方法
常见关系
常量接口
将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理,提高代码可读性
接口表示标准
接口从宏观上来讲是一种标准
public interface IUsb { void service(); }
public class character { IUsb usb;
}
public class UsbDisk implements IUsb{ public void service() { System.out.println("Usb service started1"); } }
public class UsbFan implements IUsb{ public void service() { System.out.println("Usb service started2"); } }
public class Test{ public static void main(String[] args) { UsbDisk disk = new UsbDisk(); UsbFan fan = new UsbFan(); character c=new character(); c.usb=disk; c.usb.service(); } }
|
接口除了表示约束 表示规范 接口还表示一种标记
接口回调
先有接口的使用,后有接口的实现
public interface ICallback { void call();
default void doCall(){ call(); } }
public class Test{ public static void main(String[] args) { ICallback call =new CallBack(); call.doCall(); } }
public class CallBack implements ICallback { public void call(){ System.out.println("call!"); } }
|
总结
接口优势:
- 程序的耦合度降低
- 更自然的使用多态
- 设计与实现完全分离
- 更容易搭建程序框架
- 更容易更换具体实现