赞
踩
20世纪90年代,单片式计算机系统诞生,单片式计算机系统不仅廉价,而且功能强大,使用它可以大幅度提升消费性电子产品的智能化程度
SUN公司为了抢占市场先机,在1991年成立了一个由詹姆斯·高斯林(James Gosling)领导,名为“Green”项目小组,目的是开发一种能够在各种消费性电子产品上运行的程序架构
那么使用何种编程语言来设计,是项目小组头疼的事。当时C++较为有优势的,项目小组首先考虑的是采用它来编写程序,但C++过于复杂和庞大,再加上由于消费电子产品所采用的嵌入式处理器芯片的种类繁杂,需要让编写的程序跨平台运行,假如用C++编写的话对程序的跨平台运行不友好
最后项目小组决定:既不用C++编写,也不开发全新的编程语言,而是对C++进行改造:去除了C++复杂的指针和内存管理,并结合嵌入式系统的实时性要求,最终在1992年,他们开发了一种名为“Oak”的面向对象语言
当他们在向硬件生产商进行演示的时候,硬件生产商对此并不感冒,OaK语言因为缺乏硬件的支持而无法进入市场,从而被搁置一旁
1994年,项目小组看到了浏览器在未来的发展前景,于是决定将OaK应用于万维网。1995年,他们用OaK语言研发了一种能将小程序嵌入到网页中执行的技术——Applet,由于Applet不仅能嵌入网页,还可随同网页在网络上进行传输,这让无数的程序员看到了OaK这门语言,与此同时,OaK正式更名为Java。从此,Java在互联网的推动下火了
1991年 Green项目,开发语言最初命名为Oak (橡树)
1994年,开发组意识到Oak 非常适合于互联网
1996年,发布JDK1.0,约8.3万个网页应用Java技术来制作
1997年,发布JDK 1.1,JavaOne会议召开,创当时全球同类会议规模之最
1998年,发布JDK 1.2,同年发布企业平台J2EE
1999年,Java分成J2SE、J2EE和J2ME,JSP/Servlet技术诞生
2004年,发布里程碑式版本:JDK1.5,为突出此版本的重要性,更名为JDK 5.0
2005年,J2SE -> JavaSE,J2EE -> JavaEE,J2ME -> JavaME
2009年,Oracle公司收购SUN,交易价格74亿美元
2011年,发布JDK 7.0
2014年,发布JDK 8.0,是继JDK 5.0以来变化最大的版本
2017年,发布JDK 9.0,最大限度实现模块化
2018年3月,发布JDK 10.0,版本号也称为18.3
2018年9月,发布JDK 11.0,版本号也称为18.9
Java SE: Java Platform,Standard Edition
标准版: 各应用平台的基础,桌面开发和低端商务应用的解决方案
Java EE: Java Platform,Enterprise Edition
企业版: 以企业为环境而开发应用程序的解决方案
Java ME : Java Platform, Micro Edition
微型版: 致力于消费产品 和嵌入式设备的最佳解决方案
一种纯面向对象的编程语言
一种与平台无关(跨平台)的语言。(它提供了在不同平台下运行的解释环境)
一种健壮的语言,吸收了C/C++语言的优点
有较高的安全性(自动回收垃圾,强制类型检查,取消指针)
Java虚拟机(Java Virtual Machine) JVM
垃圾回收器(Garbage Collection) GC
JVM可以理解成一个可运行Java字节码的虚拟计算机系统
它有一个解释器组件,可以实现Java字节码和计算机操作系统之间的通信
对于不同的运行平台,有不同 的JVM
JVM屏蔽了底层运行平台的差别,实现了“一次编译,随处运行”
不再使用的内存空间应当进行回收-垃圾回收
在C/C++等语言中,由程序员负责回收无用内存
Java语言消除了程序员回收无用内存空间的责任
JVM提供了一个系统线程 , 用于跟踪存储空间的分配情况 , 检查并释放那些可以被释放的存储空间
垃圾回收器在Java程序运行过程中自动启用,程序员无法精确控制和干预
JDK:Java开发工具包
JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE,所以安装了JDK,就不用在单独安装JRE了。其中的开发工具包括:编译工具(javac.exe) 打包工具(jar.exe)等
JRE:Java运行时环境
包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可
JVM:Java虚拟机
三者的关系如下
一般企业开发推荐JDK8和JDK11,Java的未来版本属于JDK17
注:常用快捷键
推荐JDK8以及以上的版本,更推荐选择JDK8或JDK11的版本
在此电脑-属性-高级系统设置-环境变量中进行配置
红线部分为jdk的安装根目录
红线部分为命令的寻址目录
注: 编写的源代码/程序的文件的后缀.java
命名规范参考Java开发手册(嵩山版)
Java对包、类、方法、参数和变量等要素命名时使用的字符序列称为标识符
命名规范: 软性建议
标识符命名习惯:见名知意
类名规范: 首字母大写,后面每个单词首字母大写(大驼峰式)
方法名规范: 首字母小写,后面每个单词首字母大写(小驼峰式)
变量名规范: 首字母小写,后面每个单词首字母大写。
包名规范:全都小写
实战案例:
\n
\r
\t
\
\ ’
\ "
注:在字符串中加上\符号,那么字符串中的转义字符将不被处理,如下
运行结果如下
Java程序有三种注释方式
格式: // 开头,行末结束
// 用于对单行代码的说明
格式: / * 开头,* / 结束
中间行的*号不是必须,只是为了格式整齐
格式: 以 /** 开始,以 */ 结束
文档注释负责描述类、接口、方法、构造器、成员属性,可以被JDK提供的工具 javadoc 所解析,自动生成一套以网页文件形式体现该程序说明文档的注释
注: 文档注释必须写在类、接口、方法、构造器、成员字段前面,写在其他位置无效
在java中未知数叫变量,未知数可能是整数,也可能是小数,java是强类型语言,要求未知数前面一定要有具体的类型(整数、小数等),因为,这些未知数也是占内存的
注:
1.没初始化的变量不能被使用(打印)
如下,声明了一个整型变量myMath,但是没有初始化,报错提示没初始化
初始化变量myMath后,没有报错
2.如下,先声明并初始化一个整型变量b,而后再赋值,变量b的值是后来再赋的值
从内存中取出变量,就算访问
注: 先声明并初始化变量后才能访问(使用)变量
给整型变量b赋值为小数,报错提示类型不匹配
如下,声明了一个整型变量,赋值为小数,报错
赋值改为整数,没有报错
实战案例
运行结果如下
计算机中的数据都以二进制数字保存
二进制:逢二进一,即只有0、1两个值
如:十进制的10在计算机内保存为二进制的1010
计算机中信息的存储单位
位(Bit): 表示一个二进制数码0或1,是计算机存储处理信息的最基本的单位
字节(Byte): 一个字节由8个位组成,第一位是符号位,0表示正,1表示负,它表示作为一个完整处理单位的8个二进制数码
字: 32位计算机:1字=32位=4字节;64位计算机:1字=64位=8字节
补充:二进制转十进制
8421法, 若是多位二进制数字,则依据2的次方依次向上叠加,二进制数字中有0则不进行计算,有1则找1对应的数字进行相加即可
二进制表示法太冗长,所以在程序中一般喜欢用十六进制
十六进制:基数为十六,逢十六进一。它用abcdef表示从0-9之上的值
Java中十六进制数据要以0x或0X开头,如:0x23D
十六进制转换成二进制只需将每个十六进制数字替换为相对应的四个二进制位即可
八进制:基数为八
Java中八进制数据要以0开头。如:0123
八进制转换成二进制:只需将每个八进制数字替换为相对应的三个二进制位即可
现在的计算机系统很少用八进制的了
java的基本数据类型共8种,如下
1.整数数字默认是int类型(即直接量是int),若要声明long类型的,需要在变量的值后面添加L后缀(不区分大小写),也可以省略(省略的时候暗含类型转换)
如下图,声明并初始化了一个变量b,不加l后缀出现报错,报错提示变量的值超出范围
添加L后缀后,报错取消
2.整数做除法,结果还是整数,并且不能四舍五入
3.0不能作为除数,否则运行时会报错
4.存的数过大,可能溢出,也可能报错,例子如下
报错
Integer.MAX_VALUE是整数类型中int的最大值,为2147483647
编译时报错,报错提示显示int类型的值超出范围,因为整数默认是int类型,但是int类型最大值为2147483647,这里超出了,所以报错
在long类型变量后面加上L后缀,报错取消
溢出
编译和运行都不报错,因为存的数过大,溢出了
运行后结果
5.初始化int类型的变量时也可以如下这样写
int x = 1,y = 2,z = 3;
1.有小数点的数字默认是double类型(即直接量是double),如果要声明一个float类型的变量,需要在变量值的后面添加f后缀(不区分大小写)
如下图,声明并初始化一个变量f2,不加后缀f出现报错,报错提示类型不匹配
添加后缀f后,报错取消
2.double类型可以使用科学计数法来赋值
例如,3.14e2、3.14E2表示3.14 * 10的2次方
结果为
3.浮点数是可以存整数的,因为浮点型比整型存储空间大
4.浮点数做除法,结果是浮点数
5.double声明并初始化一个0.开头的小数时,可以将0省略
如下,运行结果还是0.3
6.浮点数会丢失精度
1.语法格式:char a = 'x';
字符型的值必须使用单引号引起来,且只能存一个字符
如下,存两个字符,报错,报错提示Invalid character constant,即无效的字符常量
2.char其实是一个无符号整数,这个整数和字符进行对应,如下
3.字符集
ascii码:处理英文字母等少量的字符
iso8859-1:不处理中文
gbk、gb2312…:支持中文
unicode字符集:
存储的方式:utf-8 utf-16
注:乱码,就是因为字符集不一致
比如说数字121,在新华字典中代表“中”,在英汉字典中代表“我”,此时就会造成乱码
4.char的赋值方式如下
char a = ‘中’;
char b = 97;
char c = ‘\u535A’;
\u表示unicode值
5.如下图,在控制台打印并不是ab,因为char的底层是整数,a对应97,b对应98,两个变量相加就是两数相加
若想在控制台打印ab,可以使用字符串拼接的方式
1.boolean类型就两个值
2.结果是布尔的都是布尔表达式,true和false也是布尔表达式
3.实战案例
数据类型按容量大小排序如下
当一个存储空间大的类型转到存储空间小的类型时,正常是不让转的,但是java提供了一个强制类型转换的方式,格式如下
强制转换,可能数据会不正确
容量小的数据类型会自动转换为容量大的数据类型
有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算
byte,short,char之间不会相互转换,他们三者在计算时会先转换为int类型
如下图,计算两个byte类型相加并把结果赋给一个byte类型的值时报错,报错提示类型不匹配
强制转换类型后,报错取消
也可以不给运算结果赋值,直接在控制台打印,此时运算后的结果默认是int类型
boolean类型不能与其它数据类型运算
当把任何基本数据类型的值和字符串(String)进行连接运算时(+),基本数据类型的值将自动转化为字符串(String)类型,也就是说当+号用在字符串和其他变量中间,就变成了拼接操作
实战案例
1.练习1
2.练习2,如下图,此时在控制台输出123,因为字符串和任何数据类型拼接都会变成字符串,首先,字符串1和整型2拼接后变为字符串12,字符串12又和整型3进行拼接,变为字符串123
3.练习3
4.练习4
操作符优先级
表达式的运算按照运算符的优先顺序从高到低进行,同级运算符从左到右进行
运算符的优先次序
注:特殊
1.如下图这样赋值时(红线处),若++在后面,则先赋值再自增;若++在前面,则先自增再赋值
2.如下图,若直接打印i++,则i为10,在Java中,通过直接使用System.out.println(i++);
的语句进行打印时,结果会先打印i的当前值,然后再对i进行自增操作
请注意,打印的结果取决于该语句的执行时机和上下文,假设i是一个初始值为0的整数变量,并且该语句被执行一次,打印的结果将是0,而不是1,这是因为i++是一个后缀自增操作符,在表达式中使用时,它会先返回i的当前值,然后再对i进行自增操作,因此,在打印时,在自增之前,i的值仍然为0
如果对表达式中++i进行打印,它将返回自增后的值,例如,System.out.println(++i);
在执行后打印的结果将是1,因为++i是一个前缀自增操作符,它会先对i进行自增操作,然后再返回自增后的值进行打印
综上所述,直接打印i++的结果将是操作之前的值,而打印++i的结果将是操作之后的值
3.若把自增自减作为判断条件,则变量的值也会改变
运行结果如下
注:特殊
如下图这样赋值时(红线处),若–在后面,则先赋值再自减;若–在前面,则先自减再赋值
注:
1.自增和自减都是这样,若++在前,先做自增再做别的运算;若++在后,先做别的运算再自增
最后进行赋值操作
在Java中,“==” 是一个用于比较两个值是否相等的运算符,它可以用于比较数值、字符、布尔值以及对象引用的相等性, 当被比较的两个值相等时,表达式返回 true;当它们不相等时,表达式返回 false
在Java中,“!=” 是一个用于比较两个值是否不相等的运算符,它可以用于比较数值、字符、布尔值以及对象引用的不等性, 当被比较的两个值不相等时,表达式返回 true;当它们相等时,表达式返回 false
关系运算符,是有结果的,结果是boolean类型的
1.练习1,==
2.练习2,==
补充
&&(并且) ||(或) !(非)
关系运算符 可以理解为一个条件,如果有多个条件, 就需要用逻辑运算符来进行连接
1.练习1,&&,||
2.练习2,||
3.练习3,!
位运算即先拆分成二进制,然后按位做运算
&与运算: 若都是1结果是1,否则是0
|或运算: 若都是0则为0,有一个是1就是1
^异或: 相同为0,不同为1
>>: 转换成二进制右移 通常/2
右移原理同左移
<<: 转换成二进制左移 通常*2
左移就在后面补0,左移几位就乘以2的几次方,如下
>>>: 无符号右移,不管是正是负左侧(高位)都补0
短路与、或
如果是逻辑运算符,以boolean表达式1 && boolean表达式2为例,如果表达式1是false,java不会走表达式2,因为不论表达式2是true还是false,整体结果都是false,所以java会选择短路操作,如果是位运算,没有这个说法,两个表达式都会执行
1.练习1,+=
2.练习2,字符串拼接
3.练习3,+=,在下图这段代码中,变量 b2 的数据类型仍然是 byte,虽然在计算 b2 += 3; 这行代码时,会将右侧的表达式 b2 + 3 中的 3 隐式转换为 int 类型,但最终结果会被自动转回 byte 类型,然后再赋值给 b2
Java会进行这种隐式的类型转换是为了确保代码的兼容性和安全性。在对 b2 += 3; 进行计算时,首先将 b2 的值 2 加上 3,得到结果 5。然后,将 5 转换回 byte 类型,并将结果 5 赋值给 b2
因此,尽管在计算过程中会涉及 int 类型,但 b2 的数据类型仍然是 byte
注:若是如下图这样赋值则需要强制转换
boolean表达式?值1:值2(两个值类型一样)
解释: 如果布尔表达式为true,三目运算的值就是值1,否则是值2
1.练习1,若大于10岁结果是1,否则是0
2.练习2,判断输入的数据,若是1就显示男生,否则显示女生
左边的值是什么类型,右边就要用相应类型去承接,如下,左边"男生女生"是字符串类型,所以右边需要用字符串类型去承接
3.练习3,判断学生的成绩,90以上为A,60-90为B,否则为C
三目是可以嵌套的,如下
if是分组的,每一组if会选择一个条件进入
格式:
if(boolean表达式){
//如果boolean表达式为true,就进入该代码块
}else{
//如果boolean表达式为false,就进入该代码块
{
实战案例: 判断年龄是否到8岁,若到了8岁,就不能看动画片
格式:
if(boolean表达式){
//如果boolea表达式为true 就进入该代码块
}else if(boolean表达式){
...
}else if(boolean表达式){
...
}else if(boolean表达式){
...
}else{
//如果boolea表达式为false 就进入该代码块
}
实战案例: 判断职务
格式:
if(boolean表达式){
//如果boolea表达式为true 就进入该代码块
if(boolean表达式){
...
}else if(boolean表达式){
...
}else{
...
}
}else{
//如果boolea表达式为false 就进入该代码块
}
实战案例:
开放:到月底了,若手里还有500元以上,出去吃烧烤;若有100元以上,吃小吃部;若50-100,吃泡面;不到50,喝风
隔离:有100以上,点外卖;若50-100,吃泡面;不到50,喝风
System.out.println("请输入状态:"); String s1 = s.next(); System.out.println("请输入余额:"); int i1 = s.nextInt(); if(s1.equals("开放")){ if(i1 > 500){ System.out.println("吃烧烤喽"); }else if(i1 >= 100 && i1 <= 500){ System.out.println("勉强吃小吃部吧"); } }else if(s1.equals("隔离")){ if(i1 > 100){ System.out.println("被隔离,点外卖吧"); } }else if(s1.equals("没钱")){ if(i1 >= 50 && i1 <= 100){ System.out.println("吃康师傅红烧牛肉面"); }else if(i1 < 50){ System.out.println("别吃了哥们儿,喝西北风吧"); } }
switch(变量){
case 值1:
[break;]
case 值2:
[break;]
....
default://如果前面的case都不满足,会进入default,相当于else
}
1.练习1,判断季节
String season = "4"; switch(season){ case "春": System.out.println("好"); break; case "夏": System.out.println("真好"); break; case "秋": System.out.println("特别好"); break; case "冬": System.out.println("冬天东北有暖气,nice"); break; default: System.out.println("打错了"); }
运行后结果如下
2.练习2,判断状态,若是工作日则上课,否则休息
int week = 7; switch(week){ case 1: System.out.println("上课"); break; case 2: System.out.println("上课"); break; case 3: System.out.println("上课"); break; case 4: System.out.println("上课"); break; case 5: System.out.println("上课"); break; default: System.out.println("休息"); }
运行后结果如下
注:
1.从满足条件的case进入,一直向后执行,遇到第一个break退出,如果一直没有break的话则不会退出,default中的代码也会执行
2.季节、红绿灯、星期等这些不常改变的,非范围的会使用 switch这种方式
简化代码(case 0:case 1:)如下
switch(week){
case 1:
case 2:
case 3:
case 4:
case 5:
System.out.println("上课");
break;
case 6: case 7://可以像上面case12345一样竖着写,也可以这样横着写
System.out.println("休息");
break;
default:
System.out.println("打错了");
}
3.练习3,牛奶返利:伊利,蒙牛返5%;安慕希,金典,纯真:20%;完达山,古城:30%
Scanner s = new Scanner(System.in); System.out.println("请输入想查询返利的牛奶:"); String milk = s.next(); switch (milk){ case "伊利": case "蒙牛": System.out.println("返利5%"); break; case "安慕希": case "金典": case "纯甄": System.out.println("返利20%"); break; case "完达山": case "古城": System.out.println("返利30%"); break; default: System.out.println("输入有误,请重新输入"); }
运行后结果如下
4.练习4,判断成绩等级,60以上为等级A,否则为等级B
//练习四:60分以上等级为A,否则为B
System.out.println("请输入您的成绩:");
int score = s.nextInt();
switch(score/60){
case 1:
System.out.println("您的成绩为:A");
break;
case 0:
System.out.println("您的成绩为:B");
break;
default:
System.out.println("您的输入有误");
}
注:
1.switch中的变量也可以做一些特殊的处理,如:
switch(score/60){case 0:case 1:}这种
2.switch接收的变量有类型限制:
byte、short、char、int、String、枚举
3. 值1值2是变量的值
Scanner是一个辅助工具,Scanner是一个扫描器,会扫描在控制台(Console) 中输入的数据
System.out.println("请输入状态:"); String s1 = s.next(); System.out.println("请输入余额:"); int i1 = s.nextInt(); if(s1.equals("开放")){ if(i1 > 500){ System.out.println("吃烧烤喽"); }else if(i1 >= 100 && i1 <= 500){ System.out.println("勉强吃小吃部吧"); } }else if(s1.equals("隔离")){ if(i1 > 100){ System.out.println("被隔离,点外卖吧"); } }else if(s1.equals("没钱")){ if(i1 >= 50 && i1 <= 100){ System.out.println("吃康师傅红烧牛肉面"); }else if(i1 < 50){ System.out.println("别吃了哥们儿,喝西北风吧"); } }
运行结果如下
注:
1.nextInt接受int类型,同理,.nextDouble接受double类型
2.输入中文时,尽量将光标移到下面
3.多次测试,可能程序还没有执行完,就进行下一次测试了,会忘记关闭程序,注意定期关闭一下
循环体:我们负责写一遍,jvm帮我们执行10遍
while(boolean表达式){
//循环体
}
while(age < 8){//循环条件
System.out.println("可以看动画片");//循环体
age++;//条件变化
}
1、判断 boolean表达式,如果为true,就执行循环体
2、判断 boolean表达式,如果为true,就执行循环体
…
n、判断 boolean表达式,如果为false,就不执行循环体
//我今年n岁了,可以看动画片
while(age < 10){
System.out.println("我今年"+age+"岁了,可以看动画片");
age++;//计数
}
运行结果如下
死循环
while(true){
}
break用于退出循环,break常和if一起使用
while(true){
if(age < 10){
System.out.println("我今年"+age+"岁了,可以看动画片");
}else{
break;//退出循环
}
age++;
}
System.out.println(age);
运行结果如下
注:当break只能跳出内层循环,跳不出外层循环时,可以使用如下几种方法
1.判断一下是怎么从内层循环跳出来的,到了外层再判断一下
2.在外层循环加一个标志,如下
nn:while(){
while(){
break nn;
}
}
3.打标志位
原理同方法1
boolean flag = true;
//如果条件改变,flag变为false
if(flag == false){
break;
}
打标志位实例
Scanner s = new Scanner(System.in); System.out.println("欢迎光临本商店"); int sum = 0; boolean flag = true;//标志位 while(true){ //输入价格 System.out.println("请输入商品价格:"); int price = s.nextInt(); //输入数量 System.out.println("请输入商品数量:"); int num = s.nextInt(); //共计,继续(1),结算(2),其他键报错 sum += price*num; System.out.println("此次消费共计"+sum+"元,继续购买请按1,结算请按2"); //判断按键 int key; while(true){ key = s.nextInt(); if(key == 1){ break; }else if(key == 2){ //直接结算 flag = false; break; }else{ //按错,提示 System.out.println("输入错误,继续购买请按1,结算请按2"); } } if(flag == false){ System.out.println("此次消费共计"+sum+"元,欢迎再次光临"); break; } }
运行结果如下
continue用于跳出某一次循环
for(int i = 1;i <= 5;i++){
if(i == 3){
continue;//跳出本次循环
}
System.out.println(i);
}
运行结果如下
Scanner s = new Scanner(System.in);
System.out.println("您好,请输入密码:");
int i1 = s.nextInt();
while(true){
if(i1 != 128){//!=比较两个值是否不相等
System.out.println("您好,密码输入错误,请重新输入");
i1 = s.nextInt();
}else if(i1 == 128){
System.out.println("您好,欢迎来到本银行");
break;
}
}
输入银行密码,有次数限制
Scanner s = new Scanner(System.in); System.out.println("请输入您的密码:"); int i = s.nextInt(); int time = 1; //假设正确密码为815,共三次输入密码的机会 while(time <= 3){ if(i == 815){ System.out.println("密码正确,欢迎来到本银行办理业务"); break; }else{ if(time == 3){ System.out.println("输入的密码有误,您的次数已用尽,您的银行账户被暂时锁定"); break; } System.out.println("输入的密码有误,请重新输入:"); time++; i = s.nextInt(); } }
int l = 0; int m = 5; int n = 5; while(l <= 9){ l++; System.out.println("盖了"+l+"栋楼,还剩"+(m-l)+"亿"); if(l == n){ System.out.println("盖完了,竣工"); break; } if((m-l) == 0){ System.out.println("没钱了,不能盖楼"); break; } }
欢迎光临
请输入商品价格
5
请输入商品数量
2
共消费10元,继续购买请按1,结算请按2,退出请按3
1
请输入商品价格
6
请输入商品数量
1
共消费16元,继续购买请按1,结算请按2
2
您此次共消费16元,请付款,欢迎下次光临
Scanner s = new Scanner(System.in); System.out.println("欢迎光临本超市"); int sum = 0; while (true) { System.out.println("购买请按1,结算请按2,退出请按3"); int key = s.nextInt(); if (key == 1) { // 购买 System.out.println("请输入商品价格"); int p = s.nextInt(); System.out.println("请输入商品数量"); int n = s.nextInt(); sum += p * n; } else if (key == 2) { // 结算 System.out.println("您此次共消费" + sum + "元,请付款,欢迎下次光临"); break; } else if (key == 3) { // 退出 System.out.println("欢迎下次光临"); break; } else { // 输入有误,重新输入 System.out.println("输入有误,请重新输入"); } }
运行结果如下
do{
循环体
}while(boolean表达式);
public static void main(String[] args) {
int age = 3;
do{
System.out.println("看动漫喽");
age++;
}while(age < 7);
}
运行结果如下
for(初始化某变量(1);循环条件(2);变量变化(3)){
循环体(4)
}
运行顺序为:1…2…4…3…243…243…
注:
1.循环中的i通常是用来计数的,一直在变
2.循环体中的代码,常常利用i的变化
3.若初始化的变量在循环条件中,则这个变量只能活到循环结束,下一次循环还能使用相同的变量,如下
两次循环中用了同一个变量i1,并不报错,运行结果如下
做累加操作时用+=,涉及到累加的变量要放在for循环的外面
int sum = 1;
for(int i = 2;i <= 100;i++){
sum += i;//也可以写sum = sum + i;
}
System.out.println(sum);
运行结果如下
关于奇偶数的表示,2i-1、2i+1、 i%2!=0、i%2==1等等。修改循环中的步长:i++:步长为1;i=i+2:步长为2
for(int i1 = 1;i1 < 10;i1+=2){
System.out.println(i1);
}
运行结果如下
请输入一个正整数,-1退出
4
请输入一个正整数,-1退出
5
请输入一个正整数,-1退出
-1
您一共输入了 4个偶数,3个奇数
Scanner s = new Scanner(System.in); int o = 0;//偶数 int j = 0;//奇数 while(true){ System.out.println("请输入一个正整数,-1退出 "); int num = s.nextInt(); if(num == -1){ //退出 System.out.println("您已退出"); break; }else if(num % 2 == 0){ //偶数 System.out.println("偶数"); o++; }else if(num % 2 != 0){ //奇数 System.out.println("奇数"); j++; } } System.out.println("您一共输入了"+o+"个偶数,"+j+"个奇数");
运行结果如下
注:正式开发中,通常把判断代码放下面
注:System.out.println();会换行;System.out.print();不换行
for(int i = 1;i < 10;i++){
System.out.print("*");
}
运行结果如下
当需要处理又有行又有列这样的数据时,通常使用双层循环,也叫嵌套循环,其中,外层循环负责行,内层循环负责列
for(int i1 = 1;i1 <=3;i1++){
//循环体,这里负责打印一行
for(int i = 1;i <= 8;i++){
System.out.print("*");
}
System.out.println();//用来换行
}
运行结果如下
for(int i1 = 1;i1 <= 5;i1++){
//循环体,这里负责打印一行
for(int i = 1;i <= i1;i++){//找规律,第一行一列,第二行二列
System.out.print("*");
}
System.out.println();//用来换行
}
运行结果如下
for(int i = 1;i <= 9;i++){//9行
for(int j = 1;j <= i;j++){//9列
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println();
}
运行结果如下
Math.random()可以随机出 一个 [0,1)的小数,包括0,但不包括1
int i1 = (int)(Math.random()*100);//[0,100)
System.out.println(i1);
或者
double r = Math.random();//[0,1)
int i = (int)(r*100);//[0,100)
System.out.println(i);
练习2.1,生成4以内的随机整数
int i2 = (int)(Math.random()*4);//[0,4)
System.out.println(i2);
练习2.2,生成4以内的随机小数
double d1 = Math.random()*4;
System.out.println(d1);
(思路:把范围[5,8)-5,也就是生成[0,3)之间的随机数)
int i3 = (int)((Math.random()*3)+5);
System.out.println(i3);
Scanner s = new Scanner(System.in);
System.out.println("请输入想要练习的题数:");
int num = s.nextInt();
for(int i = 1;i <= num;i++){
int i4 = (int)(Math.random()*100);
int i5 = (int)(Math.random()*100);
System.out.println(i4+"+"+i5);
}
运行结果如下
Scanner s = new Scanner(System.in);
System.out.println("请输入想要练习的题数:");
int num = s.nextInt();
for(int i = 1;i <= num;i++){
int j = (int)(Math.random()*2);//可能是0,可能是1
int i4 = (int)(Math.random()*100);
int i5 = (int)(Math.random()*100);
if(j == 0){
System.out.println(i4+"+"+i5);
}else if(j == 1){
System.out.println(i4+"-"+i5);
}
}
运行结果如下
一个三位数,如153,1的三次方+5的三次方+3的三次方=1+125+27=153,这个数就叫水仙花数,123就不是水仙花数,找出100~999中哪些是水仙花数
int i1 = 0;//个位
int i2 = 0;//十位
int i3 = 1;//百位
//从100开始判断,到999结束
for(int i = 100;i <= 999;i++){
//把三位数中的个十百位取出来
i1 = i%10;
i2 = i/10%10;
i3 = i/100;
//判断一个数个位的三次方+十位的三次方+百位的三次方的和是否等于这个数
if(i1*i1*i1 + i2*i2*i2 + i3*i3*i3 == i){
//水仙花数
System.out.println(i);
}
}
一个球从100米高处落下,每次落地后反弹回原来高度的一半,再落下…求在第10次落地时,共经过多少米?第10次反弹了多高?
double sum = 100;//第一次落地不参与循环,所以初始值为100
double height = 100;//反弹的高度
for(int i = 1;i <= 9;i++){
sum += height;//第i+1次落地
height /= 2;
}
System.out.println(sum);
System.out.println(height/2);
运行结果如下
超市收银,继续购买请按1,结算请按2,按其他键弹出错误提示
Scanner s = new Scanner(System.in); System.out.println("欢迎光临本商店"); int sum = 0; while(true){ //输入价格 System.out.println("请输入商品价格:"); int price = s.nextInt(); //输入数量 System.out.println("请输入商品数量:"); int num = s.nextInt(); //共计,继续(1),结算(2),其他键报错 sum += price*num; System.out.println("此次消费共计"+sum+"元,继续购买请按1,结算请按2"); //判断按键 int key; while(true){ key = s.nextInt(); if(key == 1){ break; }else if(key == 2){ //直接结算 break; }else{ //按错,提示 System.out.println("输入错误,继续购买请按1,结算请按2"); } } if(key == 2){ System.out.println("此次消费共计"+sum+"元,欢迎再次光临"); break; } }
Scanner s = new Scanner(System.in); int i = (int)(Math.random()*100); int time = 0; while(true){ System.out.println("请输入您要猜的数字:"); time++; int num = s.nextInt(); if(num > i){ //大了 System.out.println("大了"); }else if(num < i){ //小了 System.out.println("小了"); }else{ //猜对 System.out.println("恭喜您猜中了"); System.out.println("您一共猜了"+time+"次"); break; } }
运行结果如下
int[] a = {};
存在数组中的数据取出的方式为:数组名[索引/下标]
int[] a = {1,3,5,7,9};//一个数组
System.out.println(a[4]);//9
若想修改数组中的数据,需先取出再重新赋值
int[] a = {1,3,5,7,9};
System.out.println(a[4]);//9
a[4] = 2;
System.out.println(a[4]);//2
动态的初始化数组
int[] b = new int[5];//创建了一个长度为5的数组
静态的初始化数组
int[] c = new int[]{1,2,3};
注:此时不要在int的中括号中写长度
方式二可以简写为,但不是什么时候都可以这样写,只能在声明的同时直接初始化的情况下才能使用,这种也是静态的初始化数组
int[] d = {1,2,2,4};
int arr[] = new int[4];
注:
1.若数据量小可以使用静态初始化方式;若数据量大可以使用动态初始化方式
2.数组什么类型都可以
3.如果我们不给数组中的元素赋值 ,数组中的元素,会有默认值:整型默认值是0;char的默认值是\u0000;浮点数的默认值是0.0;boolean的默认值是false,非基本数据类型 默认值为:null
int[] arr2 = {32,4,6,7,8,1};
System.out.println("数组的长度为:"+arr2.length);
注:数组中最后一个元素
int[] arr2 = {32,4,6,7,8,1};
System.out.println("数组最后一个元素为:"+arr2[arr2.length-1]);
注:
1.数组中元素的类型必须相同
2.数组通常和for循环合用也就是遍历,当for循环时,利用长度可以知道需要循环多少次
遍历数组,i通常从0开始,正好和数组的下标一致,arr[i]是一个常用代码,遍历的条件不再是i<10,而是i<arr.length
int[] arr = new int[10];
for(int i = 0;i <arr.length; i++){
arr[i] = i*2+2;
}
运行结果如下
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i]+"\t");
}
运行结果如下
int[] arr1 = new int[10];
for(int i = 0;i < arr1.length;i++){
arr1[i] = (int)(Math.random()*100);
}
System.out.println(Arrays.toString(arr1));
int[] arr3 = new int[10];
for(int i = 0;i < arr3.length;i++){
arr3[i] = (int)(Math.random()*10);
}
System.out.println(Arrays.toString(arr3));
int sum = 0;
for(int i = 0;i < arr3.length;i++){
sum += arr3[i];
}
//arr3[0]+arr3[1]+arr3[2]+ +arr3[arr3.length-1]
System.out.println(sum);
运行结果如下
String str = "sfgsdfs364可大可"; char[] arr = str.toCharArray(); System.out.println(Arrays.toString(arr)); int e = 0; int n = 0; int q = 0; for(int i = 0;i < arr.length;i++){ if((arr[i]<=90 && arr[i]>=65) || (arr[i]<=122 && arr[i]>=97)){ //(arr[i]<='z' && arr[i]>='a') e++; }else if(arr[i]>=48 && arr[i]<=57){ n++; }else{ q++; } } System.out.println("英文有"+e+"个,数字有"+n+"个,其他字符有"+q+"个");
运行结果如下
注:小套路
//两个数调换为--a=8,b=5
int a = 5;
int b = 8;
int c = a;
a = b;
b = c;
System.out.println("a="+a+",b="+b);
运行结果如下
int[] arr = {5,8};
// int[] arr1 = {0,0};
// arr1[0] = arr[0];
// arr[0] = arr[1];
// arr[1] = arr1[0];
int temp = arr[0];
arr[0] = arr[1];
arr[1] = temp;
System.out.println(Arrays.toString(arr));
运行结果如下
String[] arr = {"雪碧","脉动","可乐","脉动","脉动","脉动"};
int m = 0;
for(int i = 0;i<arr.length;i++){
if(arr[i].equals("脉动")){
m++;
}
}
System.out.println("您买的饮料中共有"+m+"瓶脉动");
运行结果如下
算一下班级的最高分(求数组中最大的值)
int[] score = new int[10]; for(int i = 0;i<score.length;i++){ score[i] = (int)(Math.random()*100); } System.out.println(Arrays.toString(score)); int max = 0; for(int j = 0;j < score.length;j++){ if(score[j] > max){ max = score[j]; } } System.out.println("最高分为:"+max); int a = 0; int b = 0; int c = 0; for(int j = 0;j < score.length;j++){ if(max - score[j] <= 10){ a++; }else if((max - score[j] <= 30) && (max - score[j] > 10)){ b++; }else{ c++; } } System.out.println("优秀的学生为"+a+",及格的学生为"+b+",不及格的学生为"+c);
运行结果如下
int[] arr = new int[5]; for(int i = 0;i < arr.length;i++){ arr[i] = (int)(Math.random()*10); } System.out.println(Arrays.toString(arr)); for(int i = 0;i < arr.length-1;i++){ //?轮 for(int j = 0;j < arr.length-1;j++){ //比较 if(arr[j] > arr[j+1]){ //交换 int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } System.out.println(Arrays.toString(arr));
运行结果如下
public static void main(String[] args) { int[] arr = new int[5]; for(int i = 0;i < arr.length;i++){ arr[i] = (int)(Math.random()*10); } System.out.println(Arrays.toString(arr)); for(int i = 0;i < arr.length-1;i++){ //?轮 boolean flag = true;//标志位 for(int j = 0;j < arr.length-1-i;j++){ //比较 if(arr[j] > arr[j+1]){ //交换 int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; flag = false; } } if(flag == true){ //这轮一个也没换 break; } System.out.println(Arrays.toString(arr)); }
运行结果如下
栈和堆,栈没有堆大,栈中放的是数组的名字,数组中的数据在堆中存着,并会有一个地址,也就是说,数组需要将数据存在堆中,而数组变量本身需要引用堆中的数据,这种数据类型叫引用类型,假设有一个数组int[] arr
,arr可以叫做变量也可以叫做引用
int[] arr = new int[4];//写new就是在堆中开辟一块空间 ,假设地址为:0x3f
arr[2] = 5;// 给0x3f地址中的第2的元素赋值
int[] arr1 = arr;//arr1中存的就是0x3f\
arr1[1] = 8;//这里看起来修改的是arr1数组,但其实在堆中,改的还是0x3f对应的数据
System.out.println(arr[1]);
把一段公共的代码封装起来就叫方法,方法通常是提供功能的,和main方法并列,注意别写在main里面,方法写完必须在main中进行调用,因为main是java程序的入口
public static void main(String[] args) {
yeonJun();
sunYshu();
}
public static void yeonJun(){
System.out.println("love u yeonjun");
}
public static void sunYshu(){
System.out.println("i love sys");
}
运行结果如下
修饰符(public static) void(返回值) 方法名(形式参数列表:形参){
方法体;
}
注:代码要写在方法中
如果一个方法写了返回值,就必须返回一个数据,并且返回数据的类型需要和返回值的类型相同(截止目前),如下
方法的返回值可以使用变量来接收(若没有返回值则不能接收,否则会报错),变量类型需要和方法的返回值类型对应上,如下
public static void main(String[] args) {
int[] x = array(5);//array(5)表示调用了array方法,并传入5作为参数
System.out.println(x);
}
public static int[] array(int a){
int[] arr = new int[a];
for(int i =0;i < arr.length;i++){
arr[i] = (int)(Math.random()*100);
}
return arr;//返回一个int类型的数组
}
一个方法有返回值,也可以直接输出这个方法,如下
System.out.println(Arrays.toString(array(5)));
注:return是用来结束一个方法的,如果该方法有返回值,就必须写return;如果该方法是void,可以不写return,看需求,如下
//测试void方法也可以写return,作用是结束该方法
public static void main(String[] args) {
cd(5);
}
public static void cd(int age){
if(age < 10){
return;
}
System.out.println("我已经长大了");
}
运行结果如下
此时控制台不会有任何打印,因为age小于10,所以代码运行到if中执行完return后会结束该方法,所以不会继续执行下面的代码
方法名(实际参数列表:实参);
注:方法体中定义的变量,还可以写在方法名后面的括号中(形参),写在括号中,本来是没有值的,但是在main中调用该方法时,会将值传过来(实参)
public static void main(String[] args) {
plus(2,4);
mj(4.0);
meIntroduce("yeonjun",23);
}
public static void mj(double r){
double i = 3.14*r*r;
System.out.println("圆的面积为:"+i);
}
运行结果如下
public static void main(String[] args) {
plus(2,4);
mj(4.0);
meIntroduce("yeonjun",23);
}
public static void meIntroduce(String s,int i){
System.out.println("我叫"+s+",今年"+i+"岁");
}
运行结果如下
若今天周四,学生吃饭会打折,不管是否排队都会去;若今天不是周四,学生可能去吃也可能不去取决于排队的人数,若多于5人就不吃了
若不是学生,若人数多于5人就不吃了
写个方法判断来的顾客会不会吃饭,比如输出:今天周三,是学生,排队5人,不吃
public static void main(String[] args) {
eat("周三","学生",2);
}
public static void eat(String day,String person,int num){
if(day.equals("周四") && person.equals("学生")){
//一定会去
System.out.println("去吃");
}else if(num > 5){
//不去
System.out.println("不去吃");
}else{
//会去
System.out.println("去吃");
}
}
运行结果如下
public static void main(String[] args) {
System.out.println(Arrays.toString(array(3)));
}
public static int[] array(int a){
int[] arr = new int[a];
for(int i =0;i < arr.length;i++){
arr[i] = (int)(Math.random()*100);
}
return arr;
}
运行结果如下
public static void main(String[] args) {
System.out.println(compareNum(23,4));
}
public static int compareNum(int a,int b){
if(a > b){
//返回a
return a;
}else{
//返回b
return b;
}
}
运行结果如下
注:java会发现如果不符合条件,就不会执行if代码段,那么代码中相当于没有写return,此时如果返回值不是void,那么就会报错,报错提示没有返回数据,但实际上我们真返回了,就要考虑没有返回全这种情况,如下
写全后报错消失
public static void main(String[] args) {
System.out.println(calc(4,2,"&"));
}
public static int calc(int a,int b,String c){
if(c.equals("+")){
return a+b;
}else if(c.equals("-")){
return a-b;
}else if(c.equals("*")){
return a*b;
}else{
return (a/b);
}
}
运行结果如下
方法是放在栈中的,先调用的方法放在最下面,后调用的方法放在最上面,每一个方法在被调用时,jvm都会给它分配一块空间,这一块空间叫做栈帧,每个方法执行完成后会被销毁,java也会将这块空间(即栈帧)销毁
假设main方法中定义了一个int a变量,某方法中也定义了一个int a变量,那么这两个方法中的变量并不会冲突,所以不会报错,如下图
两个方法,被调用时,会形成两个栈帧,如果是传参或者返回值,也不要求名字一定相同,如下图
方法自己调用自己叫做递归,容易造成栈溢出错误(StackOverflowError),所以递归需要有一个出口
套路:当我计算0-100的和时,找一个人(1)计算前99个数,我再用前99个数的和加100;人(1)找了一个人(2)计算前98个数,人(1)再用前98个数加99;人(2)找了一个人(3)计算前97个数,人(2)再用前97个数加98…,当计算这种类型的题时可以用递归
public static void main(String[] args) {
System.out.println(test1(100));
}
public static int test1(int num){//num可以帮我们计算0~num的和
if(num == 1){
return 1;//递归的出口
}
return test1(num-1)+num;//返回0~num的和
}
/**
* test方法帮我们计算第n个数是多少
* n是数列中的第几个数
* 返回第n位的值是多少
*/
public static void main(String[] args) {
System.out.println(test(8));
}
public static int test(int n){
if(n == 1 || n == 2){
//出口
return 1;
}
return test(n-2) + test(n-1);
}
注:在一个方法中修改数组,即使这个方法有返回值但没有接收,这个数组也已经改变了,如下
public class Demo05 { public static void main(String[] args) { int[] array = {1, 2, 3}; modifyArray(array); System.out.println(Arrays.toString(array)); // 输出:[2, 4, 6] } public static int[] modifyArray(int[] arr) { // 在这个方法内部对数组进行修改 for (int i = 0; i < arr.length; i++) { arr[i] *= 2; } // 返回修改后的数组,但没有接收返回值 return arr; } }
对于数组,可以对数组的下标进行随机操作
public class Demo02_扑克牌 { public static void main(String[] args) { String[] color = {"方块","梅花","黑桃","红桃"}; String[] num = {"A ","2 ","3 ","4 ","5 ","6 ","7 ","8 ","9 ","10 ","J ","Q ","K "}; String[] s = new String[54];//准备一个装扑克的数组 int count = 0; //给装扑克的数组赋值 for (int i = 0; i < color.length; i++) { for (int j = 0; j < num.length; j++) { s[count] = color[i] + num[j]; count++; } } s[52] = "小王"; s[53] = "大王"; System.out.println(Arrays.toString(s)); wash(s); System.out.println(Arrays.toString(s)); } /* * 洗牌的方法 */ public static void wash(String[] s){ //随机生成两个下标,让这两个位置互换一下 //套路:对于数组可以让数组的下标进行随机操作 for (int i = 0; i < 20; i++) { int i1 = (int)(Math.random()*54); int i2 = (int)(Math.random()*54); System.out.println(i1+" "+i2); //互换 String temp = s[i1]; s[i1] = s[i2]; s[i2] = temp; } }
运行结果如下
用方法写
public static void main(String[] args) { String[] color = {"♥️","♣","♠","♦"}; String[] type = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}; //生成扑克牌 System.out.println(Arrays.toString(creatPoker(color,type))); // String[] pokerArr = creatPoker(color,type); // System.out.println(Arrays.toString(pokerArr)); //洗牌 System.out.println(Arrays.toString(shuffle(creatPoker(color,type))));//这样写报错?因为没有返回值,所以不能接 // shuffle(pokerArr); // System.out.println(Arrays.toString(pokerArr)); } //生成扑克牌 public static String[] creatPoker(String[] color,String[] type){ String[] poker = new String[54]; int count = 0; for (int i = 0; i < color.length; i++) { for (int j = 0; j < type.length; j++) { poker[count] = color[i] + type[j]; count++; } } //System.out.println(count);此时count为52 poker[52] = "小王"; poker[53] = "大王"; return poker; } //洗牌 public static String[] shuffle(String[] arr){ for (int i = 0; i < 20; i++) { //定义两个随机下标 int i1 = (int)(Math.random()*54); int i2 = (int)(Math.random()*54); System.out.println(i1+"\t"+i2); //交换两个下标中的数 String temp = arr[i1]; arr[i1] = arr[i2]; arr[i2] = temp; } return arr; //System.out.println(Arrays.toString(arr)); }
public static void main(String[] args) { System.out.println(binToDec("101011")); } //1 0 1 0 1 1 1 //Math.pow(a,b);-->a的b次方 public static int binToDec(String s){ char[] arr = s.toCharArray(); int sum = 0; for(int i = 0;i < arr.length;i++){ if(arr[i] == '1'){ sum += Math.pow(2,arr.length-1-i); } } return sum; }
运行结果如下
面向对象有三大特性:继承、封装、多态
1.package包
(1)需要写在第一行
(2)同一个package下不能有重复的类名
(3)类的全限定名:包+类名,如sys.day11.Demo02
2.使用某个类,如果本包下有,默认就是使用本包下的,如果本包下没有,需要导入,但是也不一定非要导包,可以使用类的全限定名来处理,只不过导包可以简化我们代码的写法,如下
使用本包下有的类
使用别的包的类—导包
使用别的包的类—写类的全限定名
3.如果碰巧出现同时使用不同包下的同名的两个类,我们可以导一个包,另一个类,使用类的全限定名
4.java默认帮我们导入java.lang这个包下的类
5.静态导包—访问控制符
public(公共的)、default(默认的)(啥也不写,如void testDefault(){}
就是一个默认方法)、private(私有的)、protected(受保护的),作用范围为private<default<protected<public
注:private_get_set
成员变量基本上都是private修饰,方法基本上都是public修饰,前提得是非设计类的代码想要访问private修饰的成员变量,可以用getset方法,如下
private String brand; private int wheelNum; private int peopleNum; public String getBrand(){ //获取品牌 return brand; } public void setBrand(String brand){ //设置(修改)品牌 this.brand = brand; } public int getWheelNum(){ //获取轮子数 return wheelNum; } public void setWheelNum(int wheelNum){ //设置(修改)轮子数 this.wheelNum = wheelNum; } public int getPeopleNum(){ //获取核载人数 return peopleNum; } public void setPeopleNum(int peopleNum){ //设置(修改)核载人数 this.peopleNum = peopleNum; }
java允许我们自定义类型,如下
public class Dog {
String name;
String gender;
int age;
String color;
}
上方代码是一个自己定义的Dog类型
使用数据
public static void main(String[] args) {
Dog wangwang = new Dog();//创建一个变量
wangwang.name = "果果";//通过.的方式来操作里面的数据
wangwang.gender = "母";
wangwang.age = 2;
wangwang.color = "白色";
}
抽象的,对某一类实物的描述,概念上的内容
修饰符 class 类名{
//属性(成员变量)
//方法
}
Dog wangwang = new Dog();
wangwang.name = "果果";
int、short、byte、long的默认值为0;double的默认值为0.0;boolean的默认值为false;char的默认值为\u0000;引用类型的默认值为null
Dog ww3 = new Dog();
System.out.println(ww3.age);//0
System.out.println(ww3.color);//null
System.out.println(ww3.gender);//null
运行结果如下
变量名(对象).方法();
box.rightMove();
同一个类中,可以有多个方法名字相同,但是参数列表和个数、顺序和类型不能相同,否则会报错,因为java找方法按方法名和参数列表找,跟返回值无关(System.out.println();
就是方法重载)
当new一个新对象时,一定会在堆中开辟一块新空间,并且这个空间中有对象的默认属性值,这块新空间有一个地址,其他的对象也可以指向这个地址
Dog d1 = new Dog();
#无参的构造方法
public Dog(){
}
有参的构造方法
public Dog(String n,int a,String c,String g){
name = n;
age = a;
color = c;
gender = g;
}
创建对象的同时直接初始化
Dog d3 = new Dog("苹果",2,"白","女");
d3.info();
//有参的构造方法
public Dog(String n,int a,String c,String g){
name = n;
age = a;
color = c;
gender = g;
}
//无参的构造方法
public Dog(){
}
注:
1.自己写的类,如果写了有参构造,一定要配一个无参构造
2.一个类如果有成员变量,可以加构造方法来对成员变量进行初始化
//有参的构造方法
public Dog(String name,int age,String color,String gender){
this.name = name;
this.age = age;
this.color = color;
this.gender = gender;
}
调用格式:this(实参列表);
//有参的构造方法
public Dog(String n,int a,String c,String g){
name = n;
age = a;
color = c;
gender = g;
}
//无参的构造方法
public Dog(){
this("嘎嘎",3,"白","女");
}
注:若想让成员变量有自定义的默认值,则可以在无参的构造方法中调用有参的构造方法;也可以在无参的构造方法中直接赋值,如下
没调用之前运行结果如下
调用之后运行结果如下
1.调用有参的构造方法赋自定义的默认值
2.直接给变量赋默认值
普通方法(即没有static的方法)和成员变量需要由对象来调用,如果是null在调用普通方法或是成员变量(属性)会造成空指针异常(NullPointerException),如果arr数组为null,则使用arr[i]也会出现空指针异常
如下图,此时d和p之间没有形成关联,所以Person类中dog的值为空(null),所以在调用方法时会造成空指针异常,空指针异常会提示第几行出错(如下图黄色部分),所以若出现这种情况就找".“,因为大概率是”."前面的东西出错
Java中参数的传递就是值传递,若是基本类型,传的就是值;若是引用类型,传的是地址(一个引用类型只能存一个地址),因为引用类型中存的就是地址
1.定义在方法中
2.生命周期:方法调用时产生,方法结束时销毁
3.默认不被初始化
1.定义在类内,方法外
2.生命周期:对象被创建时产生,对象被垃圾回收时销毁(即没有东西指着的时候销毁)
3.默认会被初始化
题目梗概如下
/*
* 有一个Dog类
* 属性:name、age
* 方法: 吃 nn在吃 肉
* 有一个Person类
* 属性:name、Dog、四只狗
* 方法:
* 喂狗吃饭、给狗改名、换个狗、喂四只狗吃饭,给数组中的狗改名
*/
自己创建的类
public class Dog { String name; int age; public Dog() { } public Dog(String name, int age) { this.name = name; this.age = age; } public Dog(String name) { this.name = name; } public void eat(String food) { // 传什么吃什么 System.out.println(name + "在吃" + food); } } class Person { String name; Dog dog; Dog[] d = new Dog[4]; public void dogEat(String f) { // 喂狗吃饭 dog.eat(f); for (int i = 0; i < d.length; i++) { d[i].eat(f); } } public void changeName(String name) { // 给狗改名 dog.name = name; System.out.println(dog.name); } public void changeDogsName(String name,int index){ //给数组中的狗改名 this.d[index].name = name; } public void changeDog(Dog dog){ //换狗 this.dog = dog; } }
测试类
public static void main(String[] args) { Dog d = new Dog("苹果",2); //Dog d1 = new Dog("钻钻"); Person p = new Person(); p.dog = d; //p.dog = d1; p.d[0] = new Dog("苹果"); p.d[1] = new Dog("兰博"); p.d[2] = new Dog("钻石"); p.d[3] = new Dog("黄金"); p.dogEat("猪肝"); System.out.println("-------------"); // p.dogEat("鸡腿"); // p.changeName("兰博"); // p.dogEat("鸡腿"); //Person p1 = new Person(); p.dogEat("磨牙棒"); System.out.println("------------"); p.changeDog(new Dog("果果")); p.dogEat("肉"); System.out.println("--------------"); p.changeDogsName("兰兰", 2); p.dogEat("饺子"); }
运行结果如下
题目梗概如下
自己创建的类
ublic class HomeWork_Student { // 学生类 String name;// 张三,李四 String cardType;// A卡,B卡 //无参的构造方法 public HomeWork_Student() { } //有参的构造方法 public HomeWork_Student(String name,String cardType) { this.name = name; this.cardType = cardType; } } class bookRoot { // 图书管理员类 HomeWork_Student student; // 借书方法:通过传入不同的卡,借出不同的书 // 传A卡,借封神榜;传B卡,借java编程思想 public void borrowBook(HomeWork_Student student) { if (student.cardType.equals("A")) { System.out.println(student.name+"学生,手里的卡是"+student.cardType+"卡,可以借到封神榜"); } else { System.out.println(student.name+"学生,手里的卡是"+student.cardType+"卡,可以借到java编程思想"); } } }
测试类
public class HomeWork_读书管理测试 {
public static void main(String[] args) {
HomeWork_Student stu = new HomeWork_Student("yeonjun","A");
bookRoot br = new bookRoot();
br.student = stu;
br.borrowBook(stu);
System.out.println(stu.name);
}
}
运行结果如下
题目梗概如下
/*
* CPU类
* 属性:品牌,型号
* 方法:开机--> intel酷睿i9正在开机
* Disk类:
* 属性:品牌,容量
* 方法:开机--> 希捷 2T 硬盘正在开机
* 电脑类
* 属性:CPU Disk
* 方法:开机--> 如:
* intel酷睿i9正在开机
* 希捷 2T 硬盘正在开机
* 测试类:
* 创建一个电脑并让它开机
*/
自己创建的类
public class Computer { //属性 CPU cpu;//CPU也是一个类型 Disk disk; //开机的方法 public void powerUp(){ cpu.powerUp();//CPU开机 disk.powerUp();//硬盘开机 } } class CPU{ //属性 String cpuBrand;//cpu品牌:intel String type;//cpu型号:酷睿i9 //有参的构造方法 public CPU(String cpuBrand,String type){ this.cpuBrand = cpuBrand; this.type = type; } //无参的构造方法 public CPU(){ } //开机方法 public void powerUp(){ System.out.println(cpuBrand+type+"正在开机"); } } class Disk{ //属性 String diskBrand;//disk(硬盘)品牌:希捷 String cap;//disk容量:2T //有参的构造方法 public Disk(String diskBrand,String cap){ this.diskBrand = diskBrand; this.cap = cap; } //无参的构造方法 public Disk(){ } //开机方法 public void powerUp(){ System.out.println(diskBrand+cap+"正在开机"); } }
测试类
public class ComputerTest {
public static void main(String[] args) {
Computer c1 = new Computer();
c1.cpu = new CPU("intel","酷睿i9");//左侧是CPU类型,右侧需要是CPU类型的对象
c1.disk = new Disk("希捷","2T");
c1.powerUp();
}
}
运行结果如下
让T左移,打印T的场地
Box类
public class Box { // 属性 int line;// 行 int list;// 列 //构造方法,如果用户调用无参的构造方法,默认是(5,5) public Box(){ // this.line = 5; // this.list = 5; this(5,5); } public Box(int line,int list){ this.line = line; this.list = list; } // 方法 public void leftMove() { //左移 list--; } public void rightMove() { //右移 list++; } public void downMove() { //下移 line++; } public void printInfo() { System.out.println("(" + line + "," + list + ")"); } }
T类
public class T { //属性,boxes数组中有四个小盒子 Box[] boxes = new Box[4]; //方法 public T(){ //无参的构造方法 } public T(int line,int list){ //有参的构造方法 boxes[0] = new Box(line,list); boxes[1] = new Box(line,list+1); boxes[2] = new Box(line,list+2); boxes[3] = new Box(line+1,list+1); } public void moveLeft(){ //左移,想让T左移,那么T中的每个小盒子都要左移 for (int i = 0; i < boxes.length; i++) { boxes[i].leftMove(); } } public void moveRight(){ //右移,想让T右移,那么T中的每个小盒子都要右移 for (int i = 0; i < boxes.length; i++) { boxes[i].rightMove(); } } public void moveDown(){ //下移,想让T下移,那么T中的每个小盒子都要下移 for (int i = 0; i < boxes.length; i++) { boxes[i].downMove(); } } public void info(){ //打印信息,打印每一个小盒子的坐标信息 for (int i = 0; i < boxes.length; i++) { boxes[i].printInfo(); } } public void area(){ //打印T的场地 for (int i = 0; i < 10; i++) {//行 for (int j = 0; j < 10; j++) {//列 //打印一个星星 // if (i == 5 && j == 5) { // System.out.print("* "); // }else{ // System.out.print("- "); // } boolean flag = false;//标志 for (int q = 0; q < boxes.length; q++) { if(i == boxes[q].line && j == boxes[q].list){ System.out.print("* "); flag = true; //break; //在此题中break有没有均可 } } if(flag == false){ System.out.print("- "); } } System.out.println(i); } for (int i = 0; i < 10; i++) { System.out.print(i+" "); } } }
测试类
public class TTest {
public static void main(String[] args) {
T t = new T(5,5);
//t.info();
// t.moveLeft();
// System.out.println("-------------");
// t.info();
t.area();
}
}
运行结果如下
面向对象版
public class Block { // 父类,公共部分 Box[] boxes = new Box[4]; public void moveLeft() { // 左移,想让T左移,那么T中的每个小盒子都要左移 for (int i = 0; i < boxes.length; i++) { boxes[i].leftMove(); } } public void moveRight() { // 右移,想让T右移,那么T中的每个小盒子都要右移 for (int i = 0; i < boxes.length; i++) { boxes[i].rightMove(); } } public void moveDown() { // 下移,想让T下移,那么T中的每个小盒子都要下移 for (int i = 0; i < boxes.length; i++) { boxes[i].downMove(); } } public void info() { // 打印信息,打印每一个小盒子的坐标信息 for (int i = 0; i < boxes.length; i++) { boxes[i].printInfo(); } } } class T extends Block { public T() { // 无参的构造方法 } public T(int line, int list) { // 有参的构造方法 boxes[0] = new Box(line, list); boxes[1] = new Box(line, list + 1); boxes[2] = new Box(line, list + 2); boxes[3] = new Box(line + 1, list + 1); } } class L extends Block { public L() { } public L(int line, int list) { boxes[0] = new Box(line, list); boxes[1] = new Box(line + 1, list); boxes[2] = new Box(line + 2, list); boxes[3] = new Box(line + 2, list + 1); } }
题目梗概如下
public class HomeWork_Table { public static void main(String[] args) { Table t = new Table("白色"); // t.getTls()[0] = new TableLeg("白色"); // t.getTls()[1] = new TableLeg("白色"); // t.getTls()[2] = new TableLeg("白色"); // t.getTls()[3] = new TableLeg("白色"); t.infoLegs(); System.out.println("---------------"); t.changeLegsColor("黑色"); t.infoLegs(); System.out.println("-----------------"); t.changeLeg(2, new TableLeg("蓝色")); t.infoLegs(); } } class TableLeg{ private String color; public TableLeg(){ } public TableLeg(String color){ this.color = color; } public String getColor(){ return color; } public void setColor(String color){ this.color = color; } public void changeColor(String color){ //改一个桌腿的颜色 this.setColor(color); } public void info(){ System.out.println("桌腿的颜色为:"+color); } } class Table{ private TableLeg[] tls = new TableLeg[4]; public Table(){ } public Table(String color) { super(); for (int i = 0; i < tls.length; i++) { tls[i] = new TableLeg(color); } } public TableLeg[] getTls(){ return tls; } public void setTls(TableLeg[] tls){ this.tls = tls; } public void changeLegsColor(String color){ //给桌腿们改色 for (int i = 0; i < tls.length; i++) { tls[i].changeColor(color); } } public void changeLeg(int index,TableLeg tl){ //换第几个桌腿? tls[index] = tl; } public void infoLegs(){ for (int i = 0; i < tls.length; i++) { tls[i].info(); } } }
运行结果如下
注:
1.如果手里有引用类型,可以直接使用它,如可以使用它自带的方法
2.测试类是带程序入口(main方法)的类
3.基本类型赋值,直接赋值就可以;引用类型赋值,需要赋对象(在堆里找一个符合条件的对象):
(1)如果有现成的对象可以直接赋值
(2)如果没有现成的对象就new一个
int[][] arr = new int[3][4];
上面这句话让java帮我们创建了四个数组,一个大数组,还有三个一维小数组,其中大数组的长度为3,小数组们的长度为4,大数组中存的是三个小数组的地址,也就是说java会为我们创建一个长度为3的二维数组,三个长度为4的一维数组,并给一维数组赋默认值
int[][] arr = new int[3][];
上面这句话让java为我们创建一个长度为3的二维数组,并给这个二维数组中的元素们赋值为null(因为引用类型的变量默认值为null),使用时,需要给这些元素创建指定长度的数组,否则直接使用会报空指针异常
//int[] ss = new int[]{1,2,3};这是一维数组的静态初始化方式
int[][] arr02 = new int[][]{{1,3},{2,3},{1,2,3}};//可以这样写
int[][] arr03 = {{1,3},{2,3},{1,2,3}};//也可以简写为这样
数组下标越界异常指的是在访问数组元素时,使用了超出数组有效下标范围的索引,例如,数组长度为N,而使用了小于0或大于等于N的索引值
例如java.lang.ArrayIndexOutOfBoundsException: 2,2代表java在帮我们跑arr[2]的时候出现了越界
int[][] arr = new int[2][3];
for (int i = 0; i < arr.length; i++) { //arr.length表示二维数组的长度
for (int j = 0; j < arr[i].length; j++) {
//arr[i].length表示二维数组中每一个一维数组的长度
arr[i][j] = (int)(Math.random()*100);
}
}
System.out.println(Arrays.deepToString(arr)
int[][] arr1 = new int[3][];
arr1[0] = new int[4];
arr1[1] = new int[2];
for (int i = 0; i < arr1.length; i++) {
if(arr1[i] != null){
for (int j = 0; j < arr1[i].length; j++) {
arr1[i][j] = (int)(Math.random()*100);
}
}
}
//下面是打印二维数组的方式
System.out.println(Arrays.deepToString(arr1));
int[][] arr = new int[2][3];
int sum = 0;
for (int i = 0; i < arr.length; i++) { //arr.length为二维数组的长度
for (int j = 0; j < arr[i].length; j++) {
arr[i][j] = (int)(Math.random()*100);
sum = sum + arr[i][j];
}
}
System.out.println(Arrays.deepToString(arr));
System.out.println(sum);
方法区存的是类信息,它有一个特点,就是东西就一份,类信息就像一个说明书,比如说,当new对象的时候,堆里面知道这个对象有什么成员属性,靠的就是这个说明书;或者又比如说,当调用方法的时候在会在栈中生成一个栈帧,java知道生成多大栈帧,靠的也是这个类信息,类信息既没有值也不会运行
继承使用关键字extends,子类想要使用父类的代码,需要使用关键字extends,格式如下
class Dog extends Animal{
//Dog为子类,Animal为父类
}
父类中存的是公共部分的代码,具有公共部分的类,我们叫它父类、基类、超类
子类也叫子类、派生类、扩展类,子类可以用父类的代码,子类也可以有自己的方法,如下
public class Demo02_继承 { public static void main(String[] args) { Dog d = new Dog(); d.name = "果果"; d.age = 2; d.eat(); } } class Animal{ //父类 String name; int age; public void eat(){ System.out.println(name+age+"岁了,在吃零食"); } } class Dog extends Animal{ }
运行结果如下
public class Demo02_继承 { public static void main(String[] args) { Dog d = new Dog(); d.name = "果果"; d.age = 2; d.eat(); d.eatMore(); } } class Animal{ //父类 String name; int age; public void eat(){ System.out.println(name+age+"岁了,在吃零食"); } } class Dog extends Animal{ public void eatMore(){ System.out.println("吃磨牙棒"); } }
运行结果如下
注:
1.java中子类的构造方法默认会去调用父类的无参构造,如果父类没有无参构造函数,子类必须显示调用父类的其他构造函数,否则将报错
2.java送构造:给类送无参构造;给子类的构造方法中送一句话super();
3.子类调用父类的构造方法super();
4.java是单继承,一个子类只能继承一个父类
5.子类重写父类方法,访问控制符可以变大或相等,即父类如果是protected,子类可以是public或protected
6.返回值类型可以更改,但更改的返回值类型(子)跟原返回值类型(父)需要是继承关系,子类重写父类方法,返回值类型,可以是父类方法返回值类型的子类
7.子类对象不能在自己的方法内部直接访问父类的私有属性和私有方法,可以通过public修饰的getset方法来间接访问
如果子类想自己实现某些方法,不想用父类提供的,就可以重写,父类的方法,这样在调用的时候,就会直接调用子类自己重写的那个方法,如下
public class Demo02_继承 { public static void main(String[] args) { Cat c = new Cat(); c.name = "钻钻"; c.age = 3; c.eat(); } } class Animal{ //父类 String name; int age; public void eat(){ System.out.println(name+age+"岁了,在吃零食"); } } class Cat extends Animal{ //重写父类的方法 @Override public void eat(){ System.out.println("吃猫粮"); } }
运行结果如下
方法重写需要注意以下几点:
1.方法名、参数列表需要相同
2.返回值类型小于等于父类
3.修饰符大于等于父类
4.抛出的异常小于等于父类
5.重写的方法,方法上面可以用@Override注解
(1)当某个方法上面添加了@Override注解,代表当前方法是重写方法
(2)如果该方法写错了,有这个注解会报错,所以该注解,起到了一个检查的作用
父类方法
子类重写方法
如上,重写方法名和父类方法名不一致,所以报错
6.如果子类重写父类的方法,还想继续使用父类原方法的内容,需要加一个关键字super ,类似于this,如下
public class Demo02_继承 { public static void main(String[] args) { Cat c = new Cat(); c.name = "钻钻"; c.age = 3; c.eat(); } } class Animal{ //父类 String name; int age; public void eat(){ System.out.println(name+age+"岁了,在吃零食"); } } class Cat extends Animal{ //重写父类的方法 @Override public void eat(){ super.eat();//调用父类的eat方法 System.out.println("吃猫粮"); } }
运行结果如下
如果在main方法中调用别的类中有static的方法,则需要用类名.方法名的方式,如下
如果某些方法不需要对象的存在就可以使用它的功能,那么这个方法就可以设置为static方法
工具类是static的一个应用,工具类本身不需要成员变量,也不需要有对象,通常内部的方法都是static的,比如说Math、Arrays都是工具类
场景:假设华为笔记本厂商把设计资料都给我们了,咱们自己想创建一个笔记本也费劲,我们希望创建笔记本对象这件事,让厂商来做,我们只负责传入一些必需的参数
工厂类中的方法通常是static修饰
设计模式:23种,其中有一种叫工厂模式,还有一种叫单例模式,如下
/*单例模式
* 要求定义一个类,该类只能创建一个对象
* 分析:
* 1.需要将构造方法变为私有,用户就不能直接new对象了
* 2.发现一个都不能new了
* 3.写一个public的方法,相当于关了门,开了扇窗户
* 4.又发现自己写的方法外面调用不了
* 5.将该方法修改为静态方法,这样不用对象也能调用了
* 6.窗户开大了,所有人都可以通过这个方法 创建新对象
* 7.给方法中添加了if判断
* 如果已经存在一个对象,就返回该对象
* 否则创建一个新对象,并返回
* 8.我们需要找一个变量来存这个唯一的对象
* 使用了private static Dog dog;这种方式
*/
懒汉式
保证不了唯一的对象,因为dog = new Dog();
,new Dog()是需要时间的,在这个时间中如果有别的人也来调用创建对象这个方法,就会创建出两个对象,所以对象会不唯一
class Dog{ private static Dog dog = null; //这东西在方法区,需要写static因为"创建对象()"是类级别的 private Dog(){ //私有的构造方法 } public static Dog 创建对象(){ if(dog == null){ //判断唯一的对象是否已经创建 dog = new Dog(); //还没创建,新new一个,并先存到dog这个静态变量中 return dog; //并返回给用户 }else{ //如果静态变量dog中已经有对象了 return dog; // 直接返回已有的对象 } //也可以如下这样写 // if(dog == null){ // dog = new Dog(); // } // return dog; } }
饿汉式
能保证只有一个对象
class Cat{
private static Cat c = new Cat();//免去了先创建的烦恼,但是有问题类似于开机自启动
private Cat(){
}
public static Cat getCat(){
return c;
}
}
测试
在类内方法外,在构造方法之前执行,可用于通用的初始化操作,每次调用构造方法都会执行
在方法内,可以缩小变量的作用域,即变量出了局部代码块后就不能用了,如下
在类内方法外,用static修饰,在调用静态方法或静态变量时会触发静态代码块,通常是类加载时,在构造代码块之前执行,静态代码块只被加载一次,通常是给static变量进行初始化操作的(进行静态初始化操作的),不能初始化普通的成员变量,静态代码块中的变量出了大括号之后就不能用了
public static void main(String[] args) { B b = new B(); } } class A{ { System.out.println("3...我是A类的构造代码块.."); } static{ System.out.println("1...我是A类的静态代码块.."); } public A(){ System.out.println("4...我是A类的构造方法.."); } } class B extends A{ { System.out.println("5...我是B类的构造代码块.."); } static{ System.out.println("2...我是B类的静态代码块.."); } public B(){ System.out.println("6...我是B类的构造方法.."); } }
注:如上图,定义的常量写在方法外
final D d = new D();
d.name = "nn";
System.out.println(d.name);
d.name = "bb";
System.out.println(d.name);
// d = new D();//这种修改不可以
Object是所有类的父类,也叫顶级父类
注:基本数据类型和object是没有关系的,基本数据类型的包装类的父类则是object
Object中有toString方法,子类通常会重写父类的toString()方法,可以利用IDE(eclipse、idea等开发工具)自动生成重写的toString方法,调用时toString方法可以省略不写,如syso(dog)和syso(dog.toString())结果是一样的,都能输出成员变量的信息
场景:
财务处创建一个学生对象 ,身份证号是123456789
教务处理创建一个学生对象 ,身份证号是123456789
在堆中一定不是同一个对象
但在业务中,这两个学生,就应该是同一个学生
但==就比地址,所以有时不方便
== 恒等
1.对于基本数据类型, == 就直接判断是否相等
2.对于引用数据类型, == 在判断两个对象的地址是否相同
Object的equals方法是用 == 进行判断是否相等的,通常业务需求不能用恒等来判断,所以通常子类需要重写父类的equals方法,equals要求相对严格(也就是说重写equals方法必须要写下面这三条):如果两个对象恒等(即p1==p2结果为true),那么equals也相等;如果一个对象和null进行比较,结果需要返回false;如果一个对象和另一个对象类型不同,需要返回false,接下来,就可以写我们自己的比较规则了,如:我们要求Pig必须name和age都相同,才算相等,具体如下
@Override public boolean equals(Object obj) { if (this == obj) //如果恒等返回true return true; if (obj == null) //因为调用方不可能是空,否则会报空指针 return false; if (getClass() != obj.getClass()) //判断类型是否相同 return false; Pig other = (Pig) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }
之前,只要是同一个对象,这个地址值是相同的,现在两个nn不是同一个对象,但让我们人为的判断了相等(重写equals判断的),如果不改hashCode,别人会看到两个nn equals相等,但hashcode不同,所以我们在重写equals的同时,也会重写hashcode这个方法,该方法用来保证如果两个对象(p1、p2) equals相等,那么它们通过hashcode方法算出来的值一定相同
@Override
public int hashCode() {//com.easthome.day01.Dog@0x66(0x66其实不是地址,只是一个数值)
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
八个基本数据类型不是对象,所以java提供了 包装类 ,每个基本数据类型都有自己的包装类,如下
/*
* int -- Integer
* byte -- Byte
* short -- Short
* double -- Double
* float -- Float
* long -- Long
* boolean -- Boolean
* char -- Character
*/
1.自动封箱
int i1 = 2;
//下面这是赋值操作,类型需要匹配,但是java自动的将右侧的int类型封到了一个Integer对象中然后进行了赋值操作
Integer i2 = i1;//自动封箱
2.自动拆箱
int i1 = 2;
//下面这是赋值操作,类型需要匹配,但是java自动的将右侧的int类型封到了一个Integer对象中
Integer i2 = i1;//自动封箱
i1 = i2;//自动拆箱,不需要手动进行转换
1.int类型的最大值
System.out.println("----------------Integer自带的方法-----------");
System.out.println("int类型的最大值:"+Integer.MAX_VALUE);
2.将字符串转为整数Integer.valueOf();
(常用)
返回值是Integer类型
Integer i3 = Integer.valueOf("123");
System.out.println("字符串转为了整数:"+i3);
自动封箱的原理,其实是java在底层帮我们调用了Integer.valueOf(5);
i3 = Integer.valueOf(5); //传入一个int类型的5,会返回一个Integer类型的5
如下,用int类型去接也不会出错,因为自动拆箱了
注:NumberFormatException(数字格式化出错)
如下图这样打代码会报错,报错是因为字符串里装数字能按数字的形式去处理,装别的就处理不了了,所以叫数字格式化出错
3.int类型共多少位(Integer.SIZE)
System.out.println("int类型共多少位:"+Integer.SIZE);//32位
4.int类型的字节数(Integer.BYTES)
System.out.println("int类型的字节数:"+Integer.BYTES);//4字节
5.将字符串转为整数Integer.parseInt()
返回值是int类型
int i4 = Integer.parseInt("123");//双引号中也不能写英文字母否则会报错NumberFormatException
System.out.println(i4);
6.将一个Integer类型转为一个int类型intValue()
,返回值是int类型
i3 = Integer.valueOf(5); //传入一个int类型的5,会返回一个Integer类型的5
System.out.println(i3);
int i7 = i3.intValue();
自动拆箱的原理,其实是java在底层帮我们调用了i3.intValue();
注:valueOf和parseInt()的区别
两者都是把字符串转为整数,只不过返回的类型不同,看自己需要
Integer i8 = -128;
Integer i9 = -128;
System.out.println(i8 == i9);//true
解释:在方法区中有一个位置叫做常量池,存着-128~127之间的所有整数,给i8和i9赋值时会先去常量池里找,若在常量池里找到了,并且两个数还相同那么结果就为true,因为地址都是常量池,所以相同,此时,即使Integer是一个类,也是不需要new对象这种操作的;但是若超过了常量池的范围(-128-127),就需要new对象,地址不同,所以结果是false
场景如下
一个圆类
属性:半径
方法:求面积
长方形
属性:长宽
方法:求面积
提取一个公共的父类,写一个测试类
abstract class Father{
}
public abstract double area(); //半成品的方法,也叫抽象方法,没有方法体
abstract class Father{
public abstract double area(); //半成品的方法,也叫抽象方法,没有方法体
}
abstract class Square extends Father{
}
abstract class Father{
public abstract double area(); //半成品的方法,也叫抽象方法,没有方法体
}
class Square extends Father{
public double area(){
return 0;
}
}
注:重写父类的抽象方法时不能写abstract关键字
public class Demo03_抽象类 { public static void main(String[] args) { Cir c = new Cir(6); //System.out.println(c.area()); Cir c1 = new Cir(2); Cir c2 = new Cir(4); Rec r1 = new Rec(2,5); Rec r2 = new Rec(1,5); //父类数组装子类元素 Father[] arr = {c,c1,c2,r1,r2}; for (int i = 0; i < arr.length; i++) { System.out.println(arr[i].area()); } } } abstract class Father{ public abstract double area(); //半成品的方法,也叫抽象方法,没有方法体 } class Cir extends Father{ int ridius; //半径 public Cir() { super(); } public Cir(int ridius) { super(); this.ridius = ridius; } public double area(){ return 3.14*ridius*ridius; } } class Rec extends Father{ double length; //长 double width; //宽 public Rec() { super(); } public Rec(double length, double width) { super(); this.length = length; this.width = width; } public double area(){ return length*width; } }
运行结果如下
注:接口和接口之间用继承
interface Animal {
}
class Fox implements Animal {
}
interface Animal {
void test();
}
interface Animal {
}
interface A {
}
class Fox implements Animal, A {
}
interface Animal { void test(); } interface A { } class Fox implements Animal, A { public void test() { } }
interface C{
public default void eat(){
System.out.println("ccc");
}
}
interface C{
public default void eat(){
System.out.println("ccc");
}
}
class C1 implements C{
public void eat(){
C.super.eat();
System.out.println("111");
}
}
public class Demo05_jdk8接口 { public static void main(String[] args) { C1 cc = new C1(); cc.eat(); } } interface C{ public default void eat(){ System.out.println("ccc"); } } interface E{ public default void eat(){ System.out.println("ddd"); } } class C1 implements C,E{ public void eat(){ C.super.eat(); E.super.eat(); System.out.println("111"); } }
运行结果如下
public static void main(String[] args) {
Student y1 = new YJS();
}
//父类学生
abstract class Student{
}
//子类研究生
class YJS extends Student{
}
此时代码并没有运行,编译期能"."出什么取决于等号左边是什么类型(即父类是什么类型)
代码运行期间再确定应该调用哪个方法,"."调用的时候能出现什么结果取决于等号右边是什么类型(即子类是什么类型)
总结:能"."出来什么方法归左边管,能具体调用什么方法,运行出什么结果归右边管
public class Demo01_多态 { public static void main(String[] args) { Student y1 = new YJS(); y1.study(); System.out.println("-------------------"); Student k1 = new KDB(); BGB k2 = new KDB(); YJY k3 = new KDB(); k1.study(); k1.outPractice(); k2.meet(); k3.mark(); System.out.println("---------------"); } abstract class Student{ String name; //姓名 int age; //年龄 int num; //学号 //抽象方法学习 public abstract void study(); //出操 public void outPractice(){ System.out.println("在出操"); } } //子类研究生 class YJS extends Student{ //重写父类的study方法 public void study(){ System.out.println("研究生在学习"); } } //子类科代表 class KDB extends Student implements BGB,YJY{ //重写父类的study方法 public void study(){ System.out.println("科代表在学习"); } //重写接口的meet方法 public void meet(){ System.out.println("科代表在开会"); } //重写接口的mark方法 public void mark(){ System.out.println("科代表在阅卷"); } } //接口班干部 interface BGB{ //抽象方法开会 void meet(); } //接口阅卷员 interface YJY{ //抽象方法阅卷 void mark(); }
运行结果如下
子类可以向上转型为父类,如Student y1 = new YJS();
为什么需要强制转换:
不强转会报错,因为java认为貌似可以转,但又有风险(比如说ClassCastException(类型转换异常)),所以需要我们强制转换,如果我们确定没有风险(转了没问题),或者不怕丢东西,就可以强转
风险是什么:
因为父类可以指向不同的子类实例对象,由于向上转型,不会出错,但强转时, 如果Cat强转成了Dog就会出问题
编译期父类可以强转成子类,但可能会出错:ClassCastException(类型转换异常),如下
把父类s1的引用强制转换成子类YJS类
Student s1 = new KDB();
YJS y2 = (YJS)s1;
运行结果如下
总结:父类想强制转换成子类,父类指向的对象(实例)和子类必须是同一个类型,否则运行时会出错(ClassCastException(类型转换异常)),但编译期还没有报错提示
注:
如下这种不可以,会出错,如果想字符串转整数,还是需要Integer.valueOf或Integer.parseInt
String str = "dfv";
int a = (int)str;
s instanceof KDB
这句话的意思是:s指向的对象是不是KDB类型,如下代码进行判断,如果是KDB类型就进行强制转换
public static void main(String[] args) {
Student s1 = new KDB();
KDB k4 = (KDB)s1;
test1(s1);
}
public static void test1(Student s){
if (s instanceof KDB) {
System.out.println("s是科代表");
KDB k5 = (KDB)s;
}else{
System.out.println("s不是科代表");
}
}
运行结果如下
/*
* 红灯泡类
* 方法:开灯()-->发红光
* 绿灯泡类
* 方法:开灯()-->发绿光
* 灯泡类:
*
* 台灯类:
* 成员变量:灯泡
* 方法:点灯()-->
* 测试类:
*/
sys.day14.Demo02_灯泡练习
Outer.Inner inner = new Outer().new Inner();
class Outer{ String outerName; public void testOuter(){ System.out.println("外部类的方法"); } private class Inner{ String innerName; public void testInner(){ System.out.println("内部类的方法"); //内部类使用外部类 System.out.println(outerName); testOuter(); } } }
class Outer{
String nameOuter="outer";
public void testOuter(){
System.out.println("外部类的方法..."+nameOuter);
}
private class Inner{
private String nameInner = "inner";
public void testInner(){
System.out.println("内部类的方法..."+this.nameInner);
//内部类想用 外部类
System.out.println(Outer.this.nameOuter);
}
}
}
class Outer{ String outerName; public void testOuter(){ System.out.println("外部类的方法"); //外部类想使用内部类需要先创建内部类对象 Inner inner = new Inner(); System.out.println(inner.innerName); inner.testInner(); } private class Inner{ String innerName; public void testInner(){ System.out.println("内部类的方法"); } } }
class Outer01{
static String nameOuter;
public static void testOuter01(){
System.out.println("外部类的静态方法...");
}
//静态内部类
static class Inner01{
public void testInner01(){
System.out.println("haha");
}
}
}
//下面代码需要Outer01.Inner01不是private的
Outer01.Inner01 inner = new Outer01.Inner01();//创建静态内部类的实例
如Outer01.Inner01.testInner02();
就可以直接访问静态内部类的static方法
inner.testInner01();
Outer01.Inner01.testInner02();
class Outer01{ static String nameOuter; public static void testOuter01(){ System.out.println("外部类的静态方法..."); } static class Inner01{ public void testInner01(){ System.out.println("haha"); } public static void testInner02(){ System.out.println("静态内部类的 静态方法"); Outer01.testOuter01();//静态内部类中埋的不是Outer01.this,而是Outer01 } } }
class Outer01{ static String nameOuter; public static void testOuter01(){ System.out.println("外部类的静态方法..."); Inner01.testInner03(); Outer01.Inner01 inner = new Outer01.Inner01(); inner.testInner01(); } static class Inner01{ public void testInner01(){ System.out.println("haha"); } public static void testInner03(){ System.out.println("静态内部类的一个静态方法.."); } } }
public class Demo06_局部内部类 {
public static void main(String[] args) {
class A{
public void test1(){
System.out.println("玩");
}
}
A a = new A();
a.test1();
}
}
介绍如下
如果需要一个子类,但主要是需要子类实现某方法
并且,这个子类用一次就不用了,感觉对方想要的根本就不是子类而是一个方法,但java不支持直接用方法(方法一定得写到类中),所以我们不得以为这个方法建了一个类
java允许我们使用匿名类来完成上面的需求,匿名类可以理解为只想要方法,对类名没要求
public class Demo07_匿名内部类 { public static void main(String[] args) { Animal a1 = new Dog(); a1.run(); Animal a2 = new Cat(); a2.run(); //匿名内部类 Animal a3 = new Animal(){ @Override public void run(){ System.out.println("懒得创建类,你不就想让我跑步吗\n我跑给你看得了,别让我创建类了"); } }; a3.run(); Animal a4 = new Animal(){ @Override public void run() { System.out.println("又让我跑。。。。"); } }; a4.run(); } } interface Animal{ void run(); } class Dog implements Animal{ public void run(){ System.out.println("小狗在跑步"); } } class Cat implements Animal{ public void run(){ System.out.println("小猫在跑步"); } }
lambda表达式要求:父类是接口,只能有一个待实现的方法(也就是函数式接口)
类型 变量名 = (参数列表)->{方法体};
, 即(参数列表)->{方法体};
就是一个对象Animal a2 = (String food)->{System.out.println("在吃"+food);};
a2.eat("小零食");
如果一个接口只有一个待实现的方法,那么java有一个注解可以帮我们看着这个接口,如果接口中不止一个方法,就会报错,这样的接口叫做函数式接口,如下
@FunctionalInterface
interface Plus{
int test1(int a,int b);
}
@FunctionalInterface:函数式接口(只有一个待实现的方法),也就是说如果一个接口是函数式接口,写匿名内部类时就可以简化为lambda表达式
1.形参列表中的参数类型可以省略
2.如果参数列表中只有一个参数,参数列表的小括号可以省略
3.如果方法没有返回值且方法体中只有一条语句:方法体的大括号可以省略
4.如果方法有返回值并且方法体中只有一条语句:大括号和return都可以省略;要么都不省,要么都省掉
总结
创建一个对象,类型是一个接口(该接口中只有一个待实现的方法)
枚举也可以看成是一种类,它有固定的几个对象,不像别的类想生成几个对象就可以生成几个对象
public class Demo02_枚举 {
public static void main(String[] args) {
System.out.println(Season.FALL);
}
}
enum Season{
SPRING,SUMMER,FALL,WINTER;//这个就是我们定义的对象(实例),其实他们是常量,所以可以用类名.直接调用,这些实例必须写在第一行
}
public class Demo02_枚举 { public static void main(String[] args) { test1(Season.WINTER); } public static void test1(Season s){ switch(s){ case SPRING: System.out.println("春天"); break; case SUMMER: System.out.println("夏天"); break; case FALL: System.out.println("秋天"); break; case WINTER: System.out.println("冬天"); break; } } } enum Season{ SPRING,SUMMER,FALL,WINTER;//这个就是我么定义的对象(实例),其实他们是常量,所以可以用类名.直接调用,这些实例必须写在第一行 }
运行结果如下
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。