Java入门
初识java
编程语言概念
软件的内部是什么?
软件由程序+数据组成
人类给定指令一样,计算机要执行,也是会收到指令,计算机能能够识别的语言“计算机语言”“机器语言”
发展到汇编语言阶段,增加了助记符
从整个发展史可以看出编程语言越来越接近人类自然语言。基于某些场景、设计思想等原因有个更多的编程语言。
人类编程语言和计算机言语之间需要翻译,翻译分为两类:
- 编译
- 解释
编译:
Java、c、c++属于编译型语言,书写好源代码后,经过编译器的编译得到一个二进制文件,计算机执行的是那一个二进制文件
JavaScript 解释型语言 不需要经过编译器编译就能直接运行得到结果
Java语言的起源
91年sun公司green项目,智能家电,冰箱、微波炉、烤箱统一工作,收发信息,困难:家用电器的品牌方不一样
詹姆斯高斯林Java之爹
Java取名来源:
爪哇岛
语言精灵:duke
版本:目前最新17
- 标准版javaSE
- 企业版javaEE(未来走java方向的同学会再详细学习到EE的所有内容)
- 精简版手持设备比较多javaME
LTS长期支持版long time support8、11、17
基本概念和语法
同自然语言相似,编程语言也会拥有自己的类似字、词、句、文章的内容。
- 字母-符号
- 单词-标识符
- 语句-指令语句
- 文章-整个程序
学习编程语言就是要学习:
- 这一门编程语言中的字符
- 由字符组成的词,也就是关键词,类似于html标记中的标签名
- 学习组成完整程序的程序结构
- 重用前人写好的工具类工具库,提升开发效率
标识符
标识符分两大类:
1.语言内置
2.开发者自定义
标识符:打上标记帮助识别的符号,同中国人取名一样,会遵循规则
关键字:java语言内置好的,不可再被修改的,已经有自己的含义的单词。
类名可以自定义,首字母大写,主函数main已经定义好了不能更改。
自定义标识符取名要求:
-
硬性要求,即必须遵循
1.不能是关键字、保留字(未来会成为关键字的单词)
2.能够包含数字、字母、下划线、$、数字不能开头
3.大小写敏感
-
软性要求,即行业约束
1.变量(容器)名字见名知意
2.驼峰命名
3.蛇型命名法
4.首字母大写 帕斯卡命名法(Java常用)
5.不应该改变的量或叫不能变的量,叫做常量,名字全大写MALE
6.方法(函数)取名从函数名能够知道其功能(使用的作用)
数据类型
存储单位64G 128G…
计算机最小存储单位“位”只能存放0或1,对于“2”日常生活中用十进制,所以十进制和二进制是需要转换的,8个位bit组成一个字节Byte
单位 | 换算 |
---|---|
bit | – |
Byte | 1Byte=8bit |
KB | 1KB=1024Byte |
MB | 1MG=1024KB |
GB | 1GB=1024MB |
TB | 1TB=1024GB |
十进制转二进制
采用除2除余,逆序排列的方式
数据类型的分类
两大类:
1.基本数据类型
- 整型(byte、short、int、Long)
- 浮点型(小数)
- 字符型(区分字符和字符串)a、b是字符,ab是字符串
- 布尔型(对错,true或false)
整型
常用:int(记int)
类型 | 关键字 | 所占空间 | 范围 |
---|---|---|---|
字节型 | byte | 1个字节 | -27~27-1 |
短整型 | short | 2个字节 | -215~215-1 |
整型 | int(默认) | 4个字节 | -231~231-1 |
长整型 | Long | 8个字节 | -263~263-1 |
并不是存储字节越大越好的,适合自己项目(程序)去分配合理的空间。
浮点型
浮点数就是小数,分两种,double默认,常用
类型 | 关键字 | 空间(字节) |
---|---|---|
单精度浮点 | float | 4 |
双精度浮点 | double(默认) | 8 |
因为小数被保存在计算机中都是二进制,存在除不尽的情况,所以天生存在一定的精度问题
字符型
注意区分字符和字符串
类型 | 关键字 | 空间(字节) |
---|---|---|
字符 | char | 2 |
键盘上所有字母、标点、所有按键都在字符编码表上ASCll码(美国标准信息交换标准码)背65 A 97 a
布尔型
布尔只有两个值true和false表示真假
类型 | 关键字 | 空间(字节) |
---|---|---|
boolean | true(false) | 1位或1个字节 |
2.引用数据类型
变量
拥有了数据类型,就可以把各种类型的数据放进到容器(变量)里,使用声明指令让计算机在内存里面开辟一块空间去存数据。
变量允许被修改,可变的量。
语法:
数据类型 变量名字;
int number;
//声明后在赋值
number=3;
//声明后立马赋值
int number=3;
-
声明后赋值称为 变量的初始化
-
赋给变量的值必须跟数据类型匹配
-
变量没有赋值不允许被使用
-
作用域,变量能生效的范围
public class Lesson {
public static void main(String[] args) {
//告诉计算机开辟4个字节的空间,未来会去存放数据
int number;
//将数据3存放到变量number中
number=3;
//告诉计算机开辟8个字节的空间,将数据3.5存放进price变量里去
double price=3.5;
//告诉计算机开辟2个字节的空间,将数据a存放进ele变量里去
char ele='a';//字符单引号,字符串双引号
//小心float和long类型,在数字后面加上大小写的f或l皆可
// float f=3.5f;
// long l=12132121l;
//小心把布尔写成字符串
boolean d=true;
}
}
常量
分两类:
1.字面常量:20 5 iPhone
2.符号常量:Π
使用final关键字定义常量final double PI=3.14;常量不可被修改,将业务含义带入到常量值中,使用时即好识别,又不会被错改,未来修改时又可以“一处改处处变”
(之前版本中声明常量立马就要赋值)
运算符
1.算数运算符+ - * /取余%(读作取模)
int a=5;
int b=6;
int sum=a+b;
需要注意/除法是得到商,取模%是得到余数
运算过程中可能存在类型提升,也就是 整数+小数 会得到小数类型,小数同样有精度问题
赋值运算符
=、+=、-=、/=
a+=b;//就是a=a+b,a+b的和重新赋值给了a
i++;//在i的值的基础上+1;i=i+1;同理i--就是在i的值的基础上-1;
int a = 5;
int sum = a++ +10; //++在后,先将a的值赋出来+10,a再自增1
System.out.println(sum);
int a = 5;
int sum = ++a +10; //++在前,a先自增
System.out.println(sum);
关系(比较)运算符
5>6错 得到的是boolean类型的结果。>、<、>=、<=、==读作相等、!=读作不等
//数学
4<5<6
//不能像数学写连续比较,得通过一些逻辑运算符做链接 &&读作并且
4<5&&5<6 boolean
三目
判断?
语法:
表达式1?表达式2:表达式3:
判断表达式1的结果,为真就执行表达式2,为假就执行表达式3.(二选一)
int age = 20;
boolean result = age>18? true:false:
拿age的值20跟18比较。20>18为真,执行表达式2true即把true的值赋给变量result
int age = 2;
boolean result = age>18? true:false:
拿age的值2跟18比较。2>18为假,执行表达式3false即把false的值赋给变量result
逻辑运算符
与&&或||非!,Java里还有&、|读作位与和位或
- &&:同时满足一些条件
- ||:n选1
- !:取反,真的变假的,假的变真的
&& 存在短路,即表达式1&&表达式2当表达式1已经为假,压根不会再去判断表达式2,直接整体为假;一假全假
||也是短路运算符,n选1,选中了一个,就不会去判断后面的表达式选项,如果全部为假就是假;一真全真
数据类型的转换
通常发生在运算、比较的时候。
- 自动转换(隐式转换)
- 强制转换(由开发人员给定命令去转换)
//有整型+浮点型的时候,也要注意和的类型
int a=3; //4个字节
double b=2.5; // 8个字节
double sum=a+b;
//3还是3,字符‘A’转成了65
System.out.println(3+'A');//68-2=65
1.如果是数字+字符,字符转换为ASCll码对应的值
2.当出现转换,会自动往大数据类型方向转换
3.5/2;//2、5.0/2;//2.5同类型运算得到该类型,不同类型运算得到大数据类型
强制转换
语法:(想要的数据类型)值,不会四舍五入
int number=(int)3.14;//3
int number=(int)3.99;//3
//从数组也能得到字符
int a = 65;//'A'
char result=(char)a;
输出字符串拼接
快捷sout,使用字符串拼接可以帮我们明确
int a = 97;//'A'
char result=(char)a;
//数字65得到的字符是A 字符串拼接+
//System.out.println(数字65得到的字符是A);
//固定的字符用双引号引起来,会变得是变量,就别加双引号了
System.out.println(“数字”+a+“得到的字符是”+resul);
输入
需要引入一个类Scanner,默认只会引入Java.lang包,scanner属于java.util包,所以需要格外引用
//有一个Scanner类型的变量叫做scan,能接受输入,注意区分大小写
Scanner scan = new Scanner(System.in);//固定写法
System.out.println("请输入一个数");//提示用户让他干某个事情
int number =scan.nextInt();//接收来的数据放进number变量里
System.out.println("你输入的是"+number);
- 接收整数:
scan.nextInt();
- 接收字符串,比如接收他的名字:
scan.next();
- 接收小数:
scan.nextDouble();
分支语句
默认从上往下执行,但有时同样也会需要程序走分支条件、重复操作。
if
if 单分支语句
if(boolean 为真){
// 做...
}
if else
if else双分支2选1
if(boolean 为真){
// 做...
}
else{
//否则就...
}
if else if
多分支n选1
if(条件A){
//满足A做A事
}else if(条件B){
//满足B做B事
}else if(条件C){
//满足C做C事
}else{
//什么条件都不满足,做最后一项
}
System.out.println("输入成绩");
int score= scan.nextInt();
if (score>80){
System.out.println('A');
} else if (score>70) {
System.out.println('B');
} else if (score>60) {
System.out.println('C');
}else {
System.out.println("小垃圾");
}
假设76分,不满足第一个的if>80的条件,所以在第二个条件里就不需要再去判断是否大于80了
switch
也属于多分支语句
switch(要去匹配的内容){
case 值A:
// 满足A做A事
break;
case 值B:
//满足B做B事
break;
default:
//所以条件都不满足
break;
}
System.out.println("请输入一个月份");
int month= scan.nextInt();
switch (month){
// case 1:
// case 2:
// case 3:
// System.out.println("春季");
// break;
case 1,2,3:
System.out.println("春季");
break;
case 4,5,6:
System.out.println("夏季");
break;
case 7,8,9:
System.out.println("秋季");
break;
case 10,11,12:
System.out.println("冬季");
break;
}
当有多个case干同一件事,可以不每个case都写上break。default也是,根据自己的项目和需求来确定需不需要default的选项,换句话说default不是必需
case选项的顺序是可以调换的
字符串
数据类型String :引用数据类型
String name = "zhangsan"//注意首字母大写
字符串相等不能通过'相等'==去判断:'a'='a'相等只能判断基本数据类型
字符串A.equals(字符串B);//返回一个booleean值,读作字符串A跟字符串B相等吗
String name = "zhangsan";
String password = "1111222";
System.out.println("请输入账号");
String id = scan.next();
System.out.println("请输入密码");
String psw = scan.next();
//输入的账号匹配系统存入的系统账号 输入的密码匹配系统存入的密码
if (id.equals(name)&&psw.equals(password)){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
循环
for
表达式1:初始化
表达式2:范围
表达式3:自增自减
表达式4:做xxx
for(表达式1:表达式2:表达式3){
循环体表达式4
}
表达式1只会执行一次,然后进行判断,为真则执行循环体内的代码,再自增(或自减),再判断,循环往复。1-243-243-243
/*
输入一个数,判断数 质数
质数:只能被1和它本身整除 2 3 5 7 11 13 17 19...
*/
// 1. 用数字除以 1->number,统计共有多少个整除数量
System.out.println("请输入一个数:");
int number = scan.nextInt();
int count = 0;
for (int i = 1; i <= number; i++) {
if (number % i == 0) {
count++;
}
}
if (count == 2) {
System.out.println(number + "是质数");
} else {
System.out.println("不是!烦人!");
}
// 2. 数字除以 2->number-1,如果有,就证明还有数能整除
int number = 6;
boolean isFind = false; // 没找到
for (int i = 2; i < number; i++) {
if (number % i == 0) {
isFind = true; // 找到了
}
}
if (isFind) {
System.out.println("找到了还有能整除的数,不是");
} else {
System.out.println("是");
}
Scanner scan = new Scanner(System.in);
System.out.println("请输入第一个数");
int a = scan.nextInt();
System.out.println("请输入第二个数");
int b = scan.nextInt();
int sum = 0;
for (int i = a; i <= b; i++) {
sum += i;
}
System.out.println(sum);
// int number = (int) (Math.random() * 50 + 1);//Math.random()数学对象的随机数方法,每次调用都会得到一个0-1且不到
// //Math.random()*最大数+最小数
// for (int i = 1; i <= 5; i++) {
// System.out.println("请输入一个1-50的数");
// int math = scan.nextInt();
// if (math > number) {
// System.out.println("猜大了");
// } else if (math < number) {
// System.out.println("猜小了");
// } else if (math == number) {
// System.out.println("猜对了");
// break;
// }
// }
// System.out.println("正确答案是"+number);
while
也是循环语句
while(测试){
循环体
}
//while和for写法
for(int i=0;i<3;i++){
sout i;
}
int i=0;
while(i<3){
sout i;
i++
}
for使用场景在明确范围,while不明确范围
先判断,再执行
int a=1;
while(a>5){
a=5;
}
System.out.println(a);
先执行再判断
int a=1;
do{
a=5;
}
while(a>5);
System.out.println(a);
for、while前测试语句,do while后测试语句。do while再开发环境使用较少
打断
//对比break 和continue
for(int i=0;i<5;i++){
if(i==3){
break;//结束整个循环
}
}
System.out.println(i);//0 1 2
for(int i=0;i<5;i++){
if(i==3){
continue;//结束本次循环,进入下一次
}
}
System.out.println(i);//0 1 2 4
用break可以改写之前质数的题,少循环了很多遍,从而提高了代码的运行效率
int number = 6;
boolean isFind = false;//isFind 状态值
for (int i = 2; i < number; i++) {
if (number % i == 0) {
isFind = true;//找到了2-number-1之间还有很多能整除的数,确定number不是质数
break;//都不是质数了,以后的数不用再除了
}
}
if (isFind) {
System.out.println("不是");
} else {
System.out.println("是");
}
//提示框
// JOptionPane.showMessageDialog(null,"嘿嘿");
//输入框
// String str = JOptionPane.showInputDialog(null, "嘿嘿");
// System.out.println("输入的是:" + str);
// //确认取消框
// int result = JOptionPane.showConfirmDialog(null, "猜猜看");
// System.out.println(result);
数组
这么多人组织在一起?班级,多,数量多,数据以某种方式组织在一起?
数组。集合
数据,也可以像我们每一个人一样,集中合并放置在一起,进行批量存储和操作。数组就是集合当中最原始最简单的一种。
int aAge=20,bAge=18,cAge=16.....
//储存 变量名、数据赋值到变量身上
sout aAge
sout bAge
sout cAge
代码量多,步骤重复
声明
两种方式:
1.明确数据情况
2.未知数据情况
明确数据情况
声明方式:
数据类型[]数组名字={数据1,数据2,数据n};
//将整数20、18、16存进整数数组arr中;
int []arr={20,18,16}
// 表示内存中开辟了一块空间用于存储 3 个浮点数,56 也会被存储为 56.0
double [] rainFall = {12.3, 78.4, 56};
// 表示内存中开辟了一块空间用于存储 4 个字符串
String[] users = {"zhangsan", "lisi", "wangwu", "zhaoliu"};
未知数据类型
这种方式适用于不确定数组中值,只明确存放的个数。
数据类型[]数组名称=new 数据类型[个数];
int []arr=new int[2];
double []price=new double[3];
// zhangsan 123 500;lisi 456 1000;wangwu 666 1500;
String[] password = {"123", "456", "666"};
String[] username = {"zhangsan", "lisi", "wangwu"};
double[] money = {500, 1000, 1500};
访问 得到 输出lisi
都是通过有序的方式排列,访问数组元素,通过类似于像”学号“一样的东西,下标index索引,从0开始的
String[] username = {"zhangsan", "lisi", "wangwu"};//输出lisi
username[1]//通过 数组名[下标]获取到某个元素
System.out.println(username[1]);//打印username数组下标为1的那个元素
Syetem.out.println(username[bb6]);//报错 下标越界
在操作数组元素时,小心出现下标越界的情况。超出了数组范围是访问不到那个元素的
班级45个人,第一个人下标0,最后那个人下标为44 n-1.
通过”长度“length这个属性可以访问到数组的长度
user.length;//.读作 的
System.out.print(user.length);//打印user数组的长度
- print()、()方法,干的事情。
- length没有()是属性,拥有的数据。
属性,特征
遍历数组
利用下标
int[] arr = {123, 123, 53, 45, 23, 54, 324};
for (int i = 0; i < arr.length; i++) {
System.out.println("下标为"+i+"的是"+arr[i]);
}
当为止数据情况:
new int[5],
数组中存放的每一个元素都是0new double[5],
数组中存放的每一个元素都是0.0new char[5],
数组中存放的每一个元素都是ascll里 空字符new String[5],
数组中存放的每一个元素都是null
使用for each的方式同样可以拿到数组的每一个元素:
int[] arr = {12,432,443,53,53};
for(int item:arr){
System.out.println(item);
}
字符串转字符数组str.tocharArray()
返回一个字符数组:
System.out.println("请输入");
String str=scan.next();
char [] charArr=str.toCharArray();
System.out.println(charArr[0]);
数组的长度一旦声明好,不可改变
int[]arr={1,2,3};
arr[3]=4;//表示arr下标3的值为4
System.out.println(arr[3]);//报错 下标越界
数组中只能存放相同类型的数据
int[]arr={1,2,3.5};
基本数据类型和引用类型的赋值和值修改
//基本数据类型
int a = 5;
int b = a;//b=5
System.out.println("a是:"+a+",b是:"+b);//5 5
a=10;
System.out.println("a是:"+a+",b是:"+b);// 10 5
//更改一处,不会影响另一处
//引用数据类型
int [] a ={1,2,3};
int [] b = a;//把a的地址赋值给b
System.out.println(a[0]+","+b[0]);//1 1
a[0]=5;
System.out.println(a[0]+","+b[0]);//5 5
//引用类型出现赋值,是共享同一块内存空间,一处改变另一处跟着改变
拷贝
/*
a 1 2 3
b 1 2 3
a 5 2 3
b 1 2 3
*/
合并
// int[]a={1,2,3};
// int[]b={4,5,6};
// int[]c=new int[a.length+ b.length];
// for (int i=0;i<c.length;i++){
// if (i< a.length){
// c[i]=a[i];
// } else if (i>= a.length) {
// c[i]=b[i- a.length];
// }
// System.out.print(c[i]);
// }
选择排序,让一个数和它以后所有数一一比对,不满足条件,交换:
// int[] arr = {13, 25, 24, 54, 23, 14, 35};
// for (int i = 0; i < arr.length; i++) {
// for (int j = i + 1; j < arr.length; j++) {
// if (arr[i] < arr[j]) {
// int step = arr[i];
// arr[i] = arr[j];
// arr[j] = step;
// }
// }
// }
// for (int item:arr){
// System.out.println(itemr3);
// }
// //输入5个成绩,降序排序
// int[] grade = new int[5];
// for (int i = 1; i <= 5; i++) {
// System.out.println("请输入第" + i + "个成绩");
// int number = scan.nextInt();
// grade[i - 1] = number;
// }
// for (int j = 0; j < grade.length; j++) {
// for (int k = j + 1; k < grade.length; k++) {
// if (grade[j] < grade[k]) {
// int step = grade[j];
// grade[j] = grade[k];
// grade[k] = step;
// }
// }
// }
// System.out.println("降序排列是");
// for (int item : grade) {
// System.out.println(item);
}
int[] red = new int[6];//六个红球
int[] blue = new int[1];//一个蓝球
int b = (int) (Math.random() * 16 + 1);//蓝球随机数
for (int i = 0; i < red.length; i++) {
boolean flag = true;
int a = (int) (Math.random() * 33 + 1);//红球随机数
for (int j = 0; j < red.length; j++) {
if (red[j] == a) {
flag = false;//找到重复的数,弹出重新随机
i--;
break;
}
}
if (flag) {
red[i] = a;
}
}
System.out.println("红色球");
for (int item : red) {
System.out.println(item);
}
System.out.println("蓝色球");
System.out.println(b);
双色球方法2
// int[] red = new int[6];
// int b = (int) (Math.random() * 16 + 1);
// int a = (int) (Math.random() * 33 + 1);
// for (int i = 0; i < red.length; i++) {
// red[i] = a;//给每一个红色球赋值
// }
// for (int j = 0; j < red.length; j++) {//比较随机数和后一个随机数
// for (int k = j + 1; k < red.length; k++) {
// if (red[j] == red[k]) {
// red[k] = (int) (Math.random() * 33 + 1);//当两个随机数相等时重新赋一个随机数
// }
// if (red[j] < red[k]) {//降序排序
// int num = red[k];
// red[k] = red[j];
// red[j] = num;
// }
// }
// }
// System.out.println("红色球");
// for (int item : red) {
// System.out.println(item);
// }
// System.out.println("蓝色球");
// System.out.println(b);
}
函数
函数3要素 功能 参数 返回值
function方法 sout
函数除了Java语言自带的比如sout输出语句,还支持自定函数。
//计算1-100的值
int sum = 0;
for(int i = 1;i<=100;i++){
sum+=i;
}
//计算40-322的值
int sum = 0;
for(int i = 40;i<=322;i++){
sum+=i;
}
//计算20-112的和
//计算90-1999的和
从此可以看出当执行相同的事件时,代码出现重复、冗余,函数的出现就是为了解决重复
//请输入一个a,b a-c
int a = scanner.nextint();
int b = scanner.nextint();
foe(int i=a;i<=b,i++)
函数可以在任意位置使用(调用)
语法
语法分为:
- 声明(定义)
- 调用
声明:XX会用XX事,调用:让XX做XX
函数只声明不调用不会产生任何效果。换句话说,要想让函数内部内容生效就必须调用。
调用不存在的函数就会报错。
声明
语法:
修饰符 返回类型 函数名称(参数列表){ // 声明部分
// 实现部分
函数体;
}
public static void main(String[] args) {
for(int i = 1;i<=100;i++){
sum+=i;
}
}
参数说明:
-
public 公共 大家都XXXX
-
static 静态的
-
void 表示“没有返回值”
-
main 函数名字
-
(String[] args)括号里的就是参数列表
-
像这里出现的for循环就是函数体 可以有多个函数体
-
修饰符:指定访问范围(区间、方式),目前所有函数固定写作
public static
-
返回值:定义本方法在执行完毕后,是否有返回结果,以及返回哪种数据类型 ,要不要返回值根据自己的设计。
- 没有返回值,viod
- 若有返回值,书写返回的数据的类型
该函数求和int
实现登录boolean
根据自己的需要去指定返回类型和返回值
- 函数名称,见名知意,动词 login getSum 禁止取名abc之类的奇葩名称
- 参数列表,自定义,根据自己需要去设计,需要几个参数、参数类型是什么。形参(形式参数)、实参(实际参数)
在函数声明时,不确定具体数据,只确定数据类型,比如说计算a+b,只知道a是int b是int但不确定是几
函数调用时,传入1传入2,1、2就是具体数据,就是实际的值,是实参
// 功能 打印名字
// 没有参数
public static void printName(){
}
// 功能 打印名字
// 接收名字,具体要打印谁的名字不确定,但可以确定的是,名字是字符串类型zhangsan、lisi、wangwu
public static void printName(String name){
}
// 功能:打印名字
// 接收(需要)姓名、年龄
// 函数执行完毕后,返回XX类型
// 参数可以多个,每个参数之间通过,分隔
public static boolean printName(String name, int age){
}
书写位置
函数就是功能,所以函数与函数之前是独立存在的,声明,在main之外,调用在main内部,因为程序是从main开始运行的。
public class Test{
public static viod main(String[] args) {
getSum();
}
public static viod getSum(int a,int b){
System.out.println((a+b));
}
}
函数执行完,得到结果后,不一定非要在函数内部打印
return
在方法的实现部分,除了功能语句,还要注意和声明语句的配合。若函数的声明是 非 void 的,证明该方法一定有返回值,那么在该方法中就必须要有 return 关键字,后面跟上与返回类型匹配的返回值。
-
return 后面不能再有语句,类似于像循环中的 break
-
声明为 void 的方法也能有 retrurn 关键字用于终止函数执行,只是 return 后面不跟具体的返回值
-
若在 main() 方法中书写 return 表示结束主流程
需要注意的是,要保证该方法在任意执行路径下,都要有返回值。
String name = "zhangsan";
String mm = "123";
System.out.println("请输入账号");
String username = scan.next();
System.out.println("请输入密码");
String password = scan.next();
boolean f = login(username, password, name, mm);
System.out.println(f);
public static boolean login(String username, String psaaword, String name, String mm) {
boolean flag = false;
if (name.equals(username) && mm.equals(psaaword)) {
flag = true;
System.out.println("登陆成功");
}
return flag;
if (name.equals(username) && mm.equals(psaaword)) {
return true;
}else{
return false;
}
重载
通过接收的【形参类型】、【形参个数】、【参数顺序】自动匹配调用相应的函数
函数名称、形参类型、个数、顺序 组成 方法的签名
方法调用栈
函数的调用会形成方法调用栈,a里调用b,b里调用c,先被调用的后运行结束,形成先进后出的规律。
递归
函数直接或间接调用自己。当函数自己调用自己会形成类似与”死循坏“的效果,称为无限递归。
面向对象概念及定义
面向对象概述
面向对象是一种编程思想,编程范式(方式),其本身与语言无关。“编程思想”其实指的是在分析问题、编写程序时采用的一种思维方式。我们之前的编码方式其实都是采用的“面向过程”的编程思想。
不是只有Java才能使用面向对象编程,Java 在语法上直接引入了面向对象的概念,是第一门纯面向对象编程语言,它的设计完全是基于面向对象中所需要的概念,在语句层面上就能够表现面向对象的各种特征。其他语言也有模拟出面向对象的语法,比如说 js 在 ES6 中提出的 class
关键字。
对象
找个对象,人(性别不限)、活的、成年人…object东西,灯泡、天花板、桌子板电视…东西。
XXX:英语老师:女的、长发、阳光、漂亮
XXX:英语老师:女的、短发、严厉、微胖
XXX:英语老师:长发、没有眼镜、高跟鞋、温柔、严厉
特征,多个特征作用在了一个人身上,但都属于”英语老师“,对象、类,英语老师来说,还能唱英文歌、教英语这是属于行为
面向对象:
1.类
2.属性、数据
3.行为
ATM
main函数开始
登录
获取账号密码,验证,通过就成功,否则失败
存款
获取存款金额
+=
取款
获取取款金额
判断
-=、失败
面向对象ATM将ATM机看作一个对象,属性、方法(行为)都是属于机子的,而人在使用ATM机时只需要考虑
面向过程和面向对象 特点、区别
面向对象基于分析问题的参与角色,面向过程编程方式是基于分析问题域的解决步骤
一辆车、回家
A 我开着一辆车回家,绕车一圈、驾驶室、拉开、安全带、打火、后视镜、手刹、挂挡、左转灯【面向过程】
代驾、打车
B 张师傅代驾 (绕车一圈、驾驶室、拉开、安全带、打火、后视镜、手刹、挂挡、左转灯)对于自己而言,就只是上车就完了【面向对象】
面向过程设计思路从上至下(自顶向下),按照需要解决的问题功能进行划分,功能与功能之间互不干涉
面向对象设计思路则是关注对象,将相同行为、类型的”对象“组织设计在一起,各自有方法,需要时,找具体的某个人、某个对象就行了
面向过程和面向对象哪种编程方式更好?
针对情况、问题,通常都是使用的面向过程的方式去编码,不擅长的领域则是去调用别人的方法去实现自己想要的功能
- 属性:数据、特征
- 方法:能做的事情
- 类:
1.万物皆对象
2.对象因关注而产生,只关注当前问题域中的内容
类
- 人类
- 书籍
- 衣柜
类的概念:通过人脑的思维,把具有相同属性和行为的一组实体,进行归纳,抽取为共同的抽象概念。在一个问题域中我们会找到大量的同类型对象,根据类型进行编码。
想要一个温柔、严厉 英语老师,类是统称,是对象的抽象概括,对象是类的具体实例。
自定义类
class
public class 类名{//首字母大写
//属性、方法
//没有main函数
}
注意:
1.首字母大写
2.{}
里写属性、方法
3.一个Java文件只定义一个类public class Student{}
,不要形成嵌套称为”内部类“
4.类名跟文件名同名(很好避免,会直接报错提示)
属性
属性就是值数据,本质就是在声明变量然后赋值
// 访问修饰符 数据类型 变量名字;
public class Student{
public String name;
public int age;
//...
}
类是应该基于所有对象的共同特征特点,常量来说不常用。
属性的访问修饰符:
1.public目前都写成public的
2.不写
3.private 私有的
4.protected 受保护的
//数据的初始化
int [] arr=new int[5];//arr[0] 0 arr[3] 0
String []arr=new String[5]; //arr[0] null arr[3] null
5.属性值的初始化跟数组相同
方法
public class Student{
//两个属性
public String name;
public int age;
//两个方法
public void ear(){
//...
}
public void walk{
//...
}
}
//狗类
public class Dog {
public String gender;//性别
public int age;//年龄
public String varieties;//品种
public String name;//名字
public void eat() {//吃东西
}
public void walk() {//走路
}
public void janitor() {//看门
}
}
通类产生对象
new 关键字
通过new Scanner()能够得到scanner类型的s对象,那么new Dog就能得到具体的实例对象XX
//Scanner s= new Scanner;
Dog heihei=new Dog;
newXX()得到的对象称为实例对象(实例),一个类可以生成多个实例
constructor构造器
类里会默认产生一个无参构造,无参:没有参数,构造器就是一个函数,跟类名相同:
piblic Dog(){
}
//带参构造
public Dog(String name,int age,String gender){
name=name;
age=age;
gender=gender;
System.out.println("嘿嘿,"+name+age+gender);
}
Dog xiaohei=new Dog("xiaohei",8,"male");//在new对象时直接赋值
在调用直接赋值好处:
1.当对象属性过多,会使代码量更少,结构更清晰
2.阅读更易理解
- 不写构造函数时,默认的无参构造
- 显式书写了构造函数,就不会再自动生成无参构造,为避免报错,书写上一个无参构造,哪怕是不调用
- this的出现更明确了XX对象的XX属性值
public Dog(String name,int age,String gender){
this.name=name;
this.age=age;
this.gender=gender;
System.out.println("嘿嘿,"+name+age+gender);
}
this
this.
除了可以去设置this.name=name
之外,还可以调用方法this.XX
public void methodA() {
System.out.println("这是methodA");
this.methodB();
}
public void methodB() {
System.out.println("这是methodB");
}
//main
new.Student().methodA();
this()
让构造函数去共享另一个构造函数中的内容
1.根据函数的重载原则,根据传入的实参数据类型,会自动调用相应的构造
new Student();
public Student(){
this(1);
}
public Student(int num){
System.out.println("这个接收num的构造");//被打印
}
2.this()只能在一个构造里使用一次
public Student(){
this(1);
this("heihei");//报错
}
3.this()只能书写在构造器的第一行
4.this()不能产生递归
Student zhangsan = new Student();
zhangsan.talk(); // 我叫 zhangsan 我 18 岁 我的性别是男生
public Student() {
this("zhangsan", 18, "male");
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// main
new Student().talk();
// 无参构造
public Student() {
this("zhangsan"); // 去匹配 String 类型的构造
}
public Student(String name) {
this(18); // 去匹配 int 类型的构造
this.name = name;
}
public Student(int age) {
this(true); // 去匹配 boolean 类型的构造,不传 “male” 避免跟 public Student(String name){} 冲突
this.age = age;
}
public Student(boolean gender) {
if (gender) { // 根据接收的 true || false 决定性别
this.gender = "male";
} else {
this.gender = "female";
}
}
public void talk() {
System.out.println("我叫" + this.name + "我" + this.age + "岁,我性别:" + this.gender);
}
//方法二
public class Person {
private String name;
public String gender;
public int age;
public Person() {
this("张三", "男", 18);
}
public Person(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public void talk() {
System.out.println("我叫" + this.name + "今年" + this.age + "性别" + this.gender);
}
}
super
this 控制当前对象,这个对象,是张三是李四很明确到底是哪个对象
- this.把接收来的name赋值给this.name”这个对象的XX“属性
- this()允许A构造器调用(使用)B构造器
super
- super()子类在调用父类的构造
- super.父类的属性
1.this()super()不能同时存在
2.不要去声明跟父类同名的属性,违背了”共有属性“,但是也可以通过this.和super.去分别访问
对象的关联关系
1.张三有个小狗叫小黑
- 2个类 张三name,小狗name
2.李四在用刀切菜
- 3个类 李四,刀,菜
3.砂锅比铁锅更适合炖汤
- 1个类 锅
1.有个have has-a
,指在一个对象内部拥有另一个对象
2.用use-a
,指在一个对象的某个方法中需要使用到另一个对象
3.锅分类is-a
,指一个对象是另一个对象的特例,通常指继承关系
has-a
为了关联这种has-a的关系,会把一个对象,作为另一个对象的属性
use-a
使用关系就不应该作为属性存在,直接传参
Person lisi=new Person("lisi");
Knife dao=new Knife("菜刀");
lisi.cook(dao);
package
html CSS文件通过文件夹去进行管理。
序越来越大,书写的类越来越多,文件们就需要一种结构能够进行存放和管理。于是就有了包的概念去分门别类地管理多个类。包在本质上就是用来专门管理 java 类的文件夹。
创建包的方式:对 src 文件夹右键 - 新建 - 软件包。包的命名规范:全小写。尽量符合项目规则
特点:
1.在包里新建的类,代码顶部就会自动生成package+包名
比如说package heihei;
2.java SE 含有100多个包,基础的类都被放在java.lang包里,不用额外import去引入,而像Scanner\Date都要额外引入的,属于util包
3.import java.util.*;
使用*号可以引入某个包里所有类,但是不推荐这么操作
4.不同的包里可能存在同名的类,由此可见能够避免命名冲突
5.一个类的访问修饰符public能够提供给外部类使用(无论在不在同包)
- 一个类的访问修饰符没有public的类就只能提供给本包的类使用
package a;
public class A {
public String name="a包里的B";
}
package b;
public class B {
public String name="b包里的A";
}
public class Test {
public static void main(String[] args) {
a.A aObj = new a.A();
System.out.println(aObj.name);
b.B bObj = new b.B();
System.out.println(bObj.name);
}
}
getter访问器
实例的属性访问除了通过打印实例.属性
的方法获取以外,还可以通过访问器getter函数
右键生成-getter,选择需要生成getter的属性
public String getName(){
return name;
}
实例调用完该方法就会返回具体的值
System.out.println(s.gentName());//得到具体的值
setter设置器
对象属性赋值可以:
1.赋值符号赋值
2.调用setter
public void setGender(String gender){
this.gender=gender;
}
//调用 设置性别函数,通过参数,设置值
s.setGender("female);
对于设置的数据值的有效性判断、控制
public void setScore(int score){
if(score>=0){
this.score=score;
}else{
this.score=0;
}
}
s.setScore(20);//s.setScore(-20);
对于一些数据,并不想要公开给予访问、修改,把属性的访问修饰符设置为私有,就更好的提供了数据的安全性
private int id = 123;//私有属性
1.带上无参构造public Student(){}
2.为重要数据信息添加setter和getter的函数
//主函数
public class Grademain {
public static void main(String[] args) {
Student[] stuArr = new Student[5];
Scanner scan = new Scanner(System.in);
for (int i = 0; i < stuArr.length; i++) {
System.out.println("请输入第" + (i + 1) + "个学生名字");
String stuName = scan.next();
System.out.println("请输入第" + (i + 1) + "个学生成绩");
int stuGrade = scan.nextInt();
Student stu = new Student(stuName, stuGrade);//实例
stuArr[i] = stu;
}
sort(stuArr);
for (Student item : stuArr) {
System.out.print("学生:" + item.getName());
System.out.println("成绩: " + item.getGrade());
}
}
//排序函数
public static void sort(Student[] stuArr) {
for (int j = 0; j < stuArr.length; j++) {
for (int k = j + 1; k < stuArr.length; k++) {
if (stuArr[j].getGrade() < stuArr[k].getGrade()) {
Student value = stuArr[j];
stuArr[j] = stuArr[k];
stuArr[k] = value;
}
}
}
}
}
//学生类
public class Student {
private String name;
private int grade;
public static String[] stuNameArr = new String[5];
public static int[] stuGradeArr = new int[5];
public Student(String stuName) {
}
public Student(int stuGrade) {
}
public Student(String name, int grade) {
this.name = name;
this.grade = grade;
}
public String getName() {
return name;
}
public int getGrade() {
return grade;
}
public void setName(String name) {
this.name = name;
}
public void setGrade(int grade) {
this.grade = grade;
}
}
GC
垃圾回收机制 自动回收
Syestem.gc();
失去引用,无法再次使用,这些数据就会被认为是垃圾,被自动清理、回收。
面向对象特征
1.多态
2.继承
3.封装
4.抽象
封装
- 封装
- 继承
- 多态
- 抽象
都是面向对象的特征
封装:封–装
- 日常生活中,装:将零散的东西放在一起,方便处理和使用 封:信息隐藏,还包括对方法的具体实现的隐藏
- 函数:函数的{}就是装的内容、解决方案、函数名就是找到相应的方法的名称,封:信息隐藏,调用方不需要关注函数内部的实现,只需要关注3要素
- 类封装了:属性、方法。通过private私用访问修饰符对属性值进行信息隐藏
- 包也是在进行封装,包里装了多个类,使用public使某个或某些类公开出去供其他类使用
- 数组:装同类型的数据
int[] arr=new int[5]
Student arr2[]= new Student[5]
数组、基本数据类型数据、引用数据类型数组
- 数组:arr、arr2是数组,引用数据类型数组
- 基本数据类型数组:数组里装的是4类8种类型的数据(数组里装的是基本数据类型的数据)
- 引用数据类型数组:数组里装的是引用数据类型数据
有关静态static
区分两个概念:
1.静态方法,指的是类的方法
2.实例方法,值的是实例对象的方法
- System.out,System是个类,通过类调用的XX就是静态方法
- zhangsan.talk(),通过实例调用就是实例方法
- Math.random()静态方法
- 如果我要获取日期 年月日 实例=new Date()实例.getYear() 实例.getMonth()实例方法
static作为关键字、修饰符本身指静态,语言本身是一个严格的面对对象编程语言,要求代码全部必须出现在类里public class Tesr(...)
有时又想要针对某些属性(字段)和方法不想跟实例产生关系,用static声明的字段和方法就会作为全局的
//把数组信息为公用
public class Test{
public static 账号数组
密码数组
main{
}
//函数
public static void login{
}
}
类的属性身上,也可以有static进行修饰,有static的称为静态属性,没有static的称为非静态属性
实例可以去访问的,是非静态属性
public class Student{
public String a="普通字符串";
public static String b="静态属性";
}
Student sOjb=new Student();//学生对象 实例
System.out.println(sOjb.)//只能点出a来
类可以去访问的是静态属性
System.out.println(Student.)//点出静态的b来
证明:
- 有static的跟 类 有关
- 没有static的跟 实例 有关
如果类的静态属性被修改,所有实例去访问该值,就都被改变了(一改全改)
public class Student{
public String a="普通字符串";
public static String b="静态属性";
}
Student.b="heihei";//静态属性值被修改
System.out.println(new Student().a+","+new Student().b)//实例再去访问就已经被修改
new Student().b
通过实例依然可以得到静态属性值,但不要这样去书写,违背了”静态与类相关,非静态与实例相关“的初衷
java设计出”静态与类相关、非静态与实例相关“意图:
- 类相关的属性值就应该是全类共享
- 跟实例相关明确具体的对象
什么属性值是作为全类共享?Student,通常不会有全类共享的属性值(非static的属性居多),对于常量属性通常可以设置为类的静态属性(学生总人数)
1.访问权限 访问修饰符 public
2.常量使用final修饰
3.static
如果未来出现了可以全类共享的值,修饰符就应该是public static final
修饰
在设置属性时切记不能为了图方便就将某个、某些属性设置为static,必须是全类共享值
new Student()得到一个实例 zhangsan,new Student()得到一个实例lisi,都有自己的姓名、年龄、性别在实例自己自身,身上
static的静态属性不放在实例身上,共享内容存放在静态区里,正因为在共享区域,才导致了”一改全改“(车座子被偷走)
属性值的产生时间
- new Student()产生的是实例,在new的时候产生的值
- 静态属性在加载期产生(Test.java - 经过编译器得到.class文件 - 类加载)
static修饰方法
像Math.random()就是类去调用的方法,很明显就是静态方法。有static修饰的叫静态方法,没有static修饰的方法叫实例方法,非静态方法、成员方法
- 实例调用非静态方法
- 类调用静态方法
证明:
- 有static的跟 类 有关
- 没有static的跟 实例 有关
Math.random()
数学对象的静态方法
Math.Pl//3.141592753589793
数学对象的静态属性
初始化块
初始化块就是{}
.java允许在{}里书写所有常规语句。
构造器作用:传参,给实例对象的属性赋值,就是初始化实例对象的信息(数据)。在什么时候生效:在new的时候被调用,内部代码执行生效。
有时想要在实例化之前进行一些操作,初始化动作,就可以使用初始化块
{
//初始化内容
}
public class Student{
{
System.out.println("嘿嘿");
}
}
new Student();//嘿嘿
new Student();//嘿嘿
new类型()时初始化块里的内容就被执行。new一次执行一次,所以也叫实例初始化块
{
System.out.println("嘿嘿");
}
public Student(){
}
都是在new时进行操作、赋值,那好像做的是同一个事。初始化块会先于构造器运行,常将初始化用在进程的开始、资源、管道的开启、文件的开启等等。对于实例对象还是交给构造器。
//实例初始化块
{
//初始化内容
}
//静态初始化块
static{
}
1.静态初始化块只运行一次
2.静态初始化块优先实例初始化块运行
对比 静态初始化块 实例初始化块
相同点:
- 都会优先于构造器运行
不同点:
- 静态初始化块只运行一次,实例初始化块是new一次运行一次
- 静态初始化块是在加载器执行,实例初始化块产生对象(运行期)时执行
如果说实例初始化块的执行时间、次数、效果跟构造器差不多的话,静态初始化块时无法被替代得了。进程的开启、资源、管道的开启、文件的开启等等。需要执行一次就可以了,所以没有必要作为实例初始化块的内容,new一次开启一次。
静态初始化块使用频率>实例初始化块使用频率(0次)
继承
1.has-a
2.use-a
3.is-a 继承
判别继承关系就是看A类isB类
- 学生是人,所以学生类会拥有所有的姓名年龄性别等属性、吃饭睡觉等方法
- 狗是动物,狗类会拥有动物类所有的属性、方法
继承就是面向对象的第二个特征,提出了”类可以划分为父类和子类“的关系,所有父类具有的属性行为,子类不用再次书写。
语法:extends 表示X类继承了X类
//学生类继承了人类
public class Students extends Human{
}
子类继承父类所有属性、方法以外,还可以扩展自己的属性、方法
//父类
public class Person {
public String name;
public int age;
public String gender;
public void talk() {
System.out.println("嘿嘿");
}
}
//子类
public String name;
public int age;
public String gender;
public int score;
public White(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public White(String name, int age, String gender, int score) {
this.name = name;
this.age = age;
this.gender = gender;
this.score = score;
}
}
//主函数
public class Main {
public static void main(String[] args) {
White wti = new White("威廉姆斯", 20, "male",100);
System.out.println("我叫" + wti.name + "今年" + wti.age + "岁" + "性别" + wti.gender+"今天考了"+wti.score+"分");
wti.talk();
}
}
在new子类()时,会先调用到父类构造,父类构造不参与继承,内存叠加
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IjQJawI9-1656940226421)(C:\Users\86157\AppData\Local\Temp\1655800049426.png)]
new子类()时是不是产生了一父一子两个对象?不是。还是内存叠加的原因。父类共有部分+子类特有部分
重写
子类会拥有父类所有的方法,但有时子类的实现会跟父类定义的实现不同,就可以进行方法的重写。重写是只有函数体内实现不一样。函数名、返回值类型、参数都一致。
public class Main {
public static void main(String[] args) {
new Student().talk();
}
}
//父类
public class Person {
public void talk(){
System.out.println("吃粑粑");
}
}
//子类
public class Student extends Person {
public void talk() {
System.out.println("不吃不吃");
}
}
方法在重写时,子类的方法访问修饰符要>=父类的极限
- 父类私有,子类公开,可以
- 父类公开,子类私有,达咩
public>protected>不写,默认同包>private
对比重载重写
相同:
- 重载重写都是指的函数
- 函数名相同
- 实现的思想都是相同的行为不同的实现
不同:
重载是通过参数列表的数量、顺序、类型
重载是在一个类里的方法(重写是有继承关系)
继承的层次结构
java采取的是单继承,从上往下顺序继承,层次结构在理论上来说可以无限量,
跟手机、电视、电脑一样,可能会存在功能继承于多个类,称为多继承。人也是,除了继承爹,还有继承妈。
对比单继承和多继承:
- 多继承优点:丰富度,手机、电脑、电视可以投屏还可以打游戏、看正规网站
- 多继承缺点:形成了网状结构,结构复杂
- 单继承优点:结构简单清晰,自上而下
- 单继承缺点:灵活度、丰富度欠佳
之所有有差别就是各种语言在设计时应用场景不同而设计的,没有绝对的好坏之分。接口可以弥补这个缺陷
根类Object
java.lang包中有特殊的类Object是所有类的最上层的类,也被叫做根类。所有类都会默认继承Object
toString
java中对于toString的定义
public String toString(){
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}
System.out.println(new Studeng());
当打印某个对象实际上就会默认调用Object的toString()得到一串内存中的唯一编号形式:类的限定名字@16进制哈希值
所以当要去打印到实例的信息时。就需要对默认的toString进行重写,根据自己需要去定义toString函数体里面的内容
public String toString(){
//函数体内容自己定义,要什么返回什么
return this.name+","+this.age+","+this.gender;
}
//主函数
package object;
public class Main {
public static void main(String[] args) {
Student zs = new Student("zhangsan", "male", 18);
System.out.println(zs);
}
}
//父类
package object;
public class Human {
public String name;
public String gender;
public int age;
public Human() {
}
public Human(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String toString() {
return this.name+" "+this.gender+" "+this.age;
}
}
//子类
package object;
public class Student extends Human {
public Student() {
}
public Student(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String toString() {
return "好好学习";
}
}
equals()
java 定义的相等equals方法
public boolean equals(Object obj){
return(this==obj);
}
比较的是两个对象是否相等,还是需要去重写。java设计时并不知道后续的开发人员会拿X和X去比较索性制定了:
1.作比较的事,就用equals,省的去瞎想函数名
2.暂定用==去比较,如果开发人员有自己的需要去比较,就自己重写方法
用什么去判定两个人是否是同一人?
//主函数
package equals;
public class Main {
public static void main(String[] args) {
Student a = new Student("zhansan", "male", 18, 222);
Student b = new Student("zhansan", "male", 18, 222);
boolean d = a.equals(b);
System.out.println(d);
}
}
package equals;
public class Student {
public String name;
public String gender;
public int age;
public int id;
public Student() {
}
public Student(String name, String gender, int age, int id) {
this.name = name;
this.gender = gender;
this.age = age;
this.id = id;
}
public boolean equals(Student c) {
if (this.id == c.id) {
return true;
}else {
return false;
}
}
}
继承中的类加载
创建父类对象静态代码块
创建父类对象:new 父类()
静态代码块:static{…}
当在new父类()时,肯定是只与父类相关,又由于静态初始化块会优先于构造执行,所以静态代码块内容 - 构造内容
new Parent();//静态代码块内容-构造内容
当程序中需要使用到哪个类就加载哪个类:即时加载
创建子类对象静态代码块
new Child;//父类静态代码块 子类静态代码块 父类构造 子类构造
由于子类是继承于父类,所以也会自动加载父类,内存叠加。如果不加载父类则会有丢失父类的信息
顺序:先父类后子类,先执行静态代码块,再执行构造
new Parent();
new Child();//父类静态代码块 父类构造 子类静态代码块 父类构造 子类构造
当new 父类()肯定也只跟父类内容有关,由于静态代码块优先于构造,所以会有”父类静态代码块“”父类构造“
当new子类()由于子类继承于父类,父类的静态代码块已经被加载过了(只加载一次)所以只加载子类自己的静态代码块,再构建父类的构造内容+自己的构造内容
final
final声明常量``final double PI=3.14;`
final 特性:不可修改,还可以修饰方法,被final修饰的方法不可被修改所以也称为终态方法、最终方法
//父类
public final void talk(){
System.out.println("嘿嘿");
}
//子类
public void talk(){//报错
System.out.println("嘿嘿");
}
修饰类
被final修饰的类无法被继承,称为 终态类、最终类
public final class Parent{
}
我们通常不会去声明终态类,java设计者也不允许随便去继承类,像见过的Math、String就是终态类
多态
- 封装,在面向对象中体现的是“归纳”和“信息的隐藏”,让我们能够把现实环境的复杂内容进行归类
- 继承,在面向对象中体现的是“复用性”和“is-a关联”,表达“重复”,能够让我们通过找到类型的共性 进行进一步提取和划分
- 多态,在面向对象中体现的是丰富度,多样性、可扩展性。面对丰富的和可能不断变化的问题域让程序能有更大的容纳性去模拟、适应变化
多态这个词来源于生物学,一个生物、物种可以有多种不同的形式
- 青蛙,小时候是蝌蚪,长大是青蛙
- 边牧 黑白、陨石色灰白、金边
- 吃东西,猫狗吃肉,牛羊鹿吃草
生活中非常常见,面对对象也吸收了多态的这个特性,允许一个对象有多种形式的能力。
一个父亲带有一个方法,子类会根据自己各自需求去重新实现这个方法。在使用父类类型的引用就能调用子类里的方法。
public class Animal{
public void eat(){
System.out.println("动物吃饭");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("狗吃饭");
}
}
public class Test{
public static void main(String[] args){
Animal aObj=new Animal();
aObj.eat();//父类实例调用方法
Animal dogObj=new Dog();//子类实例
dogObj.eat();//子类方法
}
}
new子类()的实例。定义为父类类型,同样可以执行子类实例的方法
1.方法重写
2.必须存在继承关系
3.由于子类is-a父类,所以dog实例就是Animal类型Animal dogObj=new Dog;
动态绑定
实现多态的机制就是动态绑定这个机制,绑定就是将方法调用跟该方法所在类关联、固定、捆绑
动态绑定可以分为:静态绑定、动态绑定,这里的静态绑定的静态跟static无关:
- 静指的是在编译期之前就能确定,哪种类型有什么方法,Animal有eat方法,Dog也有eat方法,Student有学习方法
- 动指的是在执行期才能明确的绑定的对象类型、以及调用了哪个方法
转型
就是类型转换,在数据类型学习的时候就已经学过隐式转换(自动转换)和强制转换
基本数据类型转换规则?什么时候会发生隐式类型转换?
- 大?小?该类型能够存放数据范围
不同类型才转换
- 小范围基本数据类型 自动换为大范围基本数据类型double(8)+int(4)得到double
- 大范围基本数据类型 强制转为 小范围基本数据类型(int)Math.random()
- 强转语法:(目标类型)需要强转的值
- 强转会有精度丢失的情况
引用数据类型不能随意强转Dog类无法强转成Human类,只有在有继承关系的类时才能转换
同样存在。范围,父类的范围>子类的范围
子类沿着继承树向上继承,所以转换规则则称为向上转型
父类类型 父类名称=new 子类();
Animal dogObj=new Dog();
沿继承树向下,所以转换规则称为向下转型,基本数据类型向下转型会有精度丢失风险,引用数据类型就直接报错了
Dog dog=(Dog)new Animal();//报错 类型转换异常
多态参数
public void shoot(Gun gun){
gun.voice();
}
开闭原则:对修改关闭,对扩展开放。修改少,功能扩展
instanceof
1.运算符
2.中文含义:实例
实例 instanceof类;
使用 instanceof 可以判断出某个实例是不是属于某个类
第一种:父类属性、方法,子类重写方法。new子类()子类类型实例.方法()调用时重写后的自己的方法。
第二种:
父类类属性、方法,子类重写方法。new子类()子类类型实例.方法()调用时重写后的子类自己的方法。
第三种:
子类扩展了自己的新方法 say,子类类型实例调用 say。得到子类自己的 say 方法。
第四种:
子类扩展了自己的新方法 say,父类类型实例调用不到子类的扩展方法。
由于继承树的上下关系,子类继承父类
数组特征:
1.同一数据类型
2.长度固定
3.下标,自增
异构集合
允许将不同类型但有同类型的父类的实例集合在同一个数组里
Gun [] guns = new Gun[5];//允许放5把枪,不管是手枪、狙击枪、散弹枪等等类型
rest
rest 也被称为剩余参数,当实参传递数量不一定时,形参就不好去定义个数接收
foo(1,2,3,4,5);
public static void foo(int a,int...rest){
System.out.println("多参函数"+a);//1
System.out.println("多参函数"+rest[0]);//2
System.out.println("多参函数"+rest[1]);//3
System.out.println("多参函数"+rest[2]);//4
System.out.println("多参函数"+rest[3]);//5
}
乾坤袋
通过Object类,就可以接收各种类型的引用数据类型了
public static void foo(Object...rest){
System.out.println("多参函数"+rest[0]);
System.out.println("多参函数"+rest[1]);
}
抽象
抽象词啥意思?想象不到、只可意会、画家的画、不是具体的。
抽象类不能得到实例。
public class Animal{
public void talk(){
}
}
public class Dog extends Animal{
public void talk(){
sout"汪汪"
}
}
public class Cat extends Animal{
public void talk(){
sout"喵喵"
}
}
new Dog();
new Cat();
new Animak();
Animal、Dog、Cat 类都可以从类得到具体实例,但父类 Animal 需要实例化吗?new Animal()
到底能得到一个什么实际动物?Dog 有 Dog 的叫法,Cat 有 Cat 的叫法,各有各的实现方式,那 Animal 作为父类还有必要书写实现方法吗?
答案是否定的,父类完全没有必要实现所有逻辑,也没有必要创建父类对象。此时就可以将父类的方法抽象出来,抽象类就诞生啦!因此,当一个类在实际问题域中没有产生对象的必要,而只是为它的子类提供共有属性和方法,这种情况下就可以将其设计为抽象类。
public abstract class Animal{
}
使用abstract声明抽象类,抽象方法是只有方法声明没有方法实现:
public abstract class Animal{
public abstract void talk();//只有方法声明没有方法实现
}
子类可以继承抽象类
子类必须实现父类的抽象方法
抽象类就是专门为子类规范共有行为的类,实际运用种都是使用它的子类。
- 终态类:能得到实例,不能被继承
- 抽象类:不能得到实例,可以被继承
都是类,抽象类不能得到实例,终态类能得到实例,终态类不能被继承,抽象类可以。
在实际开发环境中,抽象类几乎不被使用。4大特征,长期以来是只有3大特征的(封装、继承、多态)
接口
对于接口来说,日常生活中也非常常见,像手机的充电线、电脑的充电线、USB插口都是接口。
只要是满足要求,无论品牌都可以使用放置在卡槽中。
js也是去操作冬天html的接口
物流公司也提供了查询物流的接口给到各个电商平台,菜鸟裹裹、淘宝、京东、抖音等,都可以查询物流信息
创建接口
在新建-接口(不是新建类)
语法:
访问修饰符 interface 接口名称{
}
- 接口的访问修饰符只能是public和同包的(如果不公开,菜鸟裹裹、淘宝、京东、抖音还怎么查得到物流信息)
- 没有构造,不能创建实例
- 没有初始化块
- 不太关注属性,主要关注行为
如果必须要定义属性,只能是public static final
的
1.接口可以让没有继承关系的类共享某个或某些方法
2.重写
//接口
public interface Eat{
public void eat();
}
//狗吃饭
public class Dog implements Eat{
public void eat(){
System.out.println("狗吃饭");
}
}
//人吃饭
public class Human implements Eat{
public void eat(){
System.out.println("人吃饭");
}
}
一个类可以拥有多个接口,使用**,**隔开
public class Dog implements Eat,Walk{
public void eat(){
System.out.println("狗吃饭");
}
public void Walk(){
System.out.println("四轮驱动");
}
}
Dog类 Human类称为实现类
,
1.is-a 继承
2.use-a使用XX
3.has-a作为属性去挂
4.like-a相像的行为
丰富了功能(丰富度)弥补了单继承的不足
继承和接口
当继承和接口想同时拥有:先继承,再接口(先extends后implements)
public class Dog extends Animal implements Eat,Walk{
}
什么内容写在父类力?什么内容写在接口里?
门
- 属性:
- 材质(木、铁、竹、合金…)
- 价格
- …
- 方法:开关门、窗子查看、把手、门铃、猫眼、密码
- 父类:开关门
- 接口:窗子查看、把手、门铃、猫眼、密码
- 与生俱来的写在父类里(没有XX功能就不是XX)
- 附属添加的写在接口里
尽量创建小(方法少)的接口,不要创建大而全的接口,避免未来修改(删除)接口时造成大面积修改
接口也可以继承接口
public interface 接口 extends 父接口1,父接口n{
}
static void foo(Object…rest){
System.out.println(“多参函数”+rest[0]);
System.out.println(“多参函数”+rest[1]);
}
### 抽象
抽象词啥意思?想象不到、只可意会、画家的画、不是具体的。
抽象类不能得到实例。
```java
public class Animal{
public void talk(){
}
}
public class Dog extends Animal{
public void talk(){
sout"汪汪"
}
}
public class Cat extends Animal{
public void talk(){
sout"喵喵"
}
}
new Dog();
new Cat();
new Animak();
Animal、Dog、Cat 类都可以从类得到具体实例,但父类 Animal 需要实例化吗?new Animal()
到底能得到一个什么实际动物?Dog 有 Dog 的叫法,Cat 有 Cat 的叫法,各有各的实现方式,那 Animal 作为父类还有必要书写实现方法吗?
答案是否定的,父类完全没有必要实现所有逻辑,也没有必要创建父类对象。此时就可以将父类的方法抽象出来,抽象类就诞生啦!因此,当一个类在实际问题域中没有产生对象的必要,而只是为它的子类提供共有属性和方法,这种情况下就可以将其设计为抽象类。
public abstract class Animal{
}
使用abstract声明抽象类,抽象方法是只有方法声明没有方法实现:
public abstract class Animal{
public abstract void talk();//只有方法声明没有方法实现
}
子类可以继承抽象类
子类必须实现父类的抽象方法
抽象类就是专门为子类规范共有行为的类,实际运用种都是使用它的子类。
- 终态类:能得到实例,不能被继承
- 抽象类:不能得到实例,可以被继承
都是类,抽象类不能得到实例,终态类能得到实例,终态类不能被继承,抽象类可以。
在实际开发环境中,抽象类几乎不被使用。4大特征,长期以来是只有3大特征的(封装、继承、多态)
接口
对于接口来说,日常生活中也非常常见,像手机的充电线、电脑的充电线、USB插口都是接口。
只要是满足要求,无论品牌都可以使用放置在卡槽中。
js也是去操作冬天html的接口
物流公司也提供了查询物流的接口给到各个电商平台,菜鸟裹裹、淘宝、京东、抖音等,都可以查询物流信息
创建接口
在新建-接口(不是新建类)
语法:
访问修饰符 interface 接口名称{
}
- 接口的访问修饰符只能是public和同包的(如果不公开,菜鸟裹裹、淘宝、京东、抖音还怎么查得到物流信息)
- 没有构造,不能创建实例
- 没有初始化块
- 不太关注属性,主要关注行为
如果必须要定义属性,只能是public static final
的
1.接口可以让没有继承关系的类共享某个或某些方法
2.重写
//接口
public interface Eat{
public void eat();
}
//狗吃饭
public class Dog implements Eat{
public void eat(){
System.out.println("狗吃饭");
}
}
//人吃饭
public class Human implements Eat{
public void eat(){
System.out.println("人吃饭");
}
}
一个类可以拥有多个接口,使用**,**隔开
public class Dog implements Eat,Walk{
public void eat(){
System.out.println("狗吃饭");
}
public void Walk(){
System.out.println("四轮驱动");
}
}
Dog类 Human类称为实现类
,
1.is-a 继承
2.use-a使用XX
3.has-a作为属性去挂
4.like-a相像的行为
丰富了功能(丰富度)弥补了单继承的不足
继承和接口
当继承和接口想同时拥有:先继承,再接口(先extends后implements)
public class Dog extends Animal implements Eat,Walk{
}
什么内容写在父类力?什么内容写在接口里?
门
- 属性:
- 材质(木、铁、竹、合金…)
- 价格
- …
- 方法:开关门、窗子查看、把手、门铃、猫眼、密码
- 父类:开关门
- 接口:窗子查看、把手、门铃、猫眼、密码
- 与生俱来的写在父类里(没有XX功能就不是XX)
- 附属添加的写在接口里
尽量创建小(方法少)的接口,不要创建大而全的接口,避免未来修改(删除)接口时造成大面积修改
接口也可以继承接口
public interface 接口 extends 父接口1,父接口n{
}