------------------------------------------------------------------------------
一、java概述
1、Java技术体系平台
JavaSE(JavaStandardEdition)标准版
支持面向桌面级应用(如Windows下的应用程序)的Java平台,提供了完整的Java核心API,此版本以前称为J2SE
JavaEE(JavaEnterpriseEdition)企业版
是为开发企业环境下的应用程序提供的一套解决方案。该技术体系中包含的技术如:Servlet、Jsp等,主要针对于Web应用程序开发,版本以前称为J2EE,学习javaEE是要以javaSE为基础的
JavaME(JavaMicroEdition)小型版
支持Java程序运行在移动终端((手机、PDA)上的平台,对JavaAPI有所精简,并加入对移动终端的支持,此版本以前称为J2ME
2、java虚拟机
JVM是一个虚拟的计算机,具有指令集并使用不同的存储区域。负责执行指令,管理数据、内存、寄存器,包含在JDK中
对于不同的平台,有不同的虚拟机,Java虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,到处运行”,所以才说java的跨平台性极好
3、JDK与JRE
JDK的全称(JavaDevelopmentKitJava开发工具包)
JDK=JRE+java的开发工具[java,javac,javadoc,javap等]
JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE。所以安装了JDK,就不用在单独安装JRE了。
JRE的全称(JavaRuntimeEnvironmentJava运行环境)
JRE=JVM+Java的核心类库[类]
包括Java虚拟机(JVMJavaVirtualMachine)和Java程序所需的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。
JDK、JRE和JVM的包含关系
①JDK=JRE+开发工具集(例如Javac,java编译工具等)
②JRE=JVM+JavaSE标准类库(java核心类库)
③如果只想运行开发好的.class文件只需要JRE
4、下载安装JDK
安装完之后需要配置环境变量
环境变量原理:当前执行的程序在当前目录下如果不存在,win10系统会在系统中已有的一个名为path的环境变量指定的目录中查找。如果仍未找到,会出现错误提示
所以需要将java用到的程序路径存入到环境变量中去
centos安装java11
卸载安装的java
查看安装的目录,并设置JAVA_HOME
java-11的安装本地目录为:/usr/lib/jvm/java-11-openjdk-11.0.15.0.9-2.el7_9.x86_64/
添加环境变量,设置设置JAVA_HOME
vi/etc/profile在文件最后添加以下代码
source/etc/profile#刷新profile文件5、java快速入门
6、java开发注意事项
1>Java源文件以.java为扩展名。源文件的基本组成部分是类(class),如本类中的Hello类
2>Java应用程序的执行入口是main()方法。
它有固定的书写格式:
publicstaticvoidmain(String[]args){...}3>Java语言严格区分大小写
4>Java方法由一条条语句构成,每个语句以“;”结束
5>大括号都是成对出现的,缺一不可,要习惯先写{}再写代码
6>一个源文件中最多只能有一个public类,其它类的个数不限
7>如果源文件包含一个public类,则文件名必须按该类名命名
8>一个源文件中最多只能有一个public类,其它类的个数不限,也可以将main方法写在非public类中,然后指定运行非public类,这样入口方法就是非public的main方法
7、如何快速掌握新技术
二、转义字符
\t#一个制表位,实现对齐的功能\n#换行符\\#输出一个\\"#输出一个"\'#输出一个'\r#一个回车示例
代码注释分为javadoc注释和单行/多行注释
javadoc注释被称为文档注释,注释内容可以被JDK提供的工具javadoc所解析,生成一套以网页文件形式体现的该程序的说明文档,一般写在类
javadoc-d文件夹名-author-versionchar.javajava开发简单规范
1、类、方法的注释,要以javadoc的方式来写注释
2、非Javadoc的注释,往往是给代码的维护者看的,着重告述读者为什么这样写,如何修改,注意什么问题等(单行,多行注释)
3、使用tab操作,实现缩进,默认整体向右边移动;用shift+tab整体向左移
4、运算符和=两边习惯性各加一个空格。比如:2+4*5+345-89
5、源文件使用utf-8编码
6、行宽度不要超过80字符
7、代码编写次行风格和行尾风格,推荐使用行尾风格
三、变量
变量是程序的基本组成单位,变量有三个基本要素(类型+名称+值),变量相当于内存中一个数据存储空间的表示
classvariable{publicstaticvoidmain(String[]args){//定义变量先intc;//再给变量赋值c=9527;System.out.println(9527);//还可以定义变量和赋值一步到位inta=1;System.out.println(a+c);}}变量使用注意事项
1、变量表示内存中的一个存储区域,不同的变量,类型不同,占用的空间大小不同
2、该区域有自己的名称[变量名]和类型[数据类型]
4、该区域的数据/值可以在同一类型范围内不断变化
5、变量在同一个作用域内不能重名
6、变量=变量名+值+数据类型,即变量三要素
程序中+号的使用
1、当左右两边都是数值型时,则做加法运算
2、当左右两边有一方为字符串,则做拼接运算
3、运算顺序从左到右
classplus{publicstaticvoidmain(String[]args){System.out.println(100+98);//198System.out.println("100"+98);//10098System.out.println(100+98+"hello");//198helloSystem.out.println("hello"+100+98);//hello10098}}四、数据类型
每一种数据都定义了明确的数据类型,在内存中分配了不同大小的内存空间(字节)
1、整型的使用细节
1>Java各整数类型有固定的范围和字段长度,不受具体OS[操作系统]的影响,以保证java程序的可移植性
4>bit:计算机中的最小存储单位;byte:计算机中基本存储单元,1byte=8bit
2、浮点类型
Java的浮点类型可以表示一个小数,比如123.4、7.8、0.12等等
1>单精度与双精度的区别
在内存中占有的字节数不同:单精度浮点数在机内占4个字节,双精度浮点数在机内占8个字节;
有效数字位数不同:单精度浮点数有效数字8位,双精度浮点数有效数字16位。
关于浮点数在机器中存放形式的简单说明:浮点数=符号位+指数位+尾数位,尾数部分可能丢失,造成精度损失(小数都是近似值)
2>使用细节
与整数类型类似,Java浮点类型也有固定的范围和字段长度,不受具体OS的影响。[float4个字节、double是8个字节]
classfolat_test{publicstaticvoidmain(String[]args){floatn=3.14F;doublem=3.14;System.out.println(n+"--"+m);}}3>浮点型常量有两种表示形式
十进制数形式,如:5.12、512.0f、.512(必须有小数点)
科学计数法形式,如:5.12e2[5.12*10的2次方]、5.12E-2[5.12/10的2次方]
4>通常情况下,应该使用double型,因为它比float型更精确
5>浮点数使用陷阱:2.7和8.1/3比较
所以得到一个重要的使用点:当我们对运算结果是小数的进行相等判断时,要小心,应该是以两个数的差值的绝对值,在某个精度范围类判断
但如果是直接查询得的小数或者直接赋值,则可以直接判断相等
classtrap{publicstaticvoidmain(String[]args){doublenum1=2.7;doublenum2=8.1/3;if(Math.abs(num1-num2)<0.00001){System.out.println("相等");}}}3、JavaAPI文档
2>Java语言提供了大量的基础类,因此Oracle公司也为这些基础类提供了相应的API文档,用于告诉开发者如何使用这些类,以及这些类里包含的方法
3>Java类的组织形式
4、字符类型char
字符类型可以表示单个字符,字符类型是char,char是两个字节(可以存放汉字),多个字符我们用字符串String
1>字符常量是用单引号(‘’)括起来的单个字符。例如:charv1='a'、charv2='辉'、charv3='9'
2>Java中还允许使用转义字符来将其后的字符转变为特殊字符型常量。例如:charv3=‘\n''\n'表示换行符
3>在java中,char的本质是一个整数,在输出时,是unicode码对应的字符
4>可以直接给char赋一个整数,然后输出时,会按照对应的unicode字符输出
5>char类型是可以进行运算的,相当于一个整数,因为它都对应有unicode码.
publicclasstest{publicstaticvoidmain(String[]args){charv1='a';charv2=98;charv3='a'+2;charv4='赵';charv5='\t';charv6='王';System.out.println(v1+""+v2+""+v3);//abcSystem.out.println(v1+v2+v3);//294System.out.println((int)v1);//97System.out.println(v4);//赵System.out.println(v5);//换行符System.out.println(v4+v6);//65792v4和v6本质上是整数,所以结果为将他的码值加起来}}字符型存储到计算机中,需要将字符对应的码值(整数)找出来,比如'a'
存储:'a'==>码值97==>二进制(1100001)==>存储
读取:二进制(1100001)==>97==>'a'==>显示
5、字符编码表
ASCII:ASCIl编码表一个字节表示,一个128个字符,实际上一个字节可以表示256个字符,只用了128个
Unicode:Unicode编码表固定大小的编码使用两个字节来表示字符,字母和汉字统一都是占用两个字节,这样浪费空间
utf-8:大小可变的编码表,字母使用1个字节,汉字使用3个字节
gbk:可以表示汉字,而且范围广,字母使用1个字节,汉字2个字节
gb2312:可以表示汉字,gb2312 big5码:繁体中文、台湾、香港 ASCII码介绍 上个世纪60年代,美国制定了一套字符编码(使用一个字节),对英语字符与二进制位之间的关系,做了统一的规定。这被称为ASCII码 ASCII码一共规定了128个字符的编码,只占用了一个字节的后面7位,最前面的1位统一规定为0 特别提示:一个字节可以表示256个字符,ASCII码只用了128个字符. 缺点:不能表示所有字符。 Unicode编码介绍 Unicode的好处:一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,使用Unicode没有乱码的问题 Unicode的缺点:一个英文字母和一个汉字都占用2个字节,这对于存储空间来说是浪费 2的16次方是65536,所以汉字最多编码是65536个字符 编码0-127的字符是与ASCII的编码一样.比如'a'在ASCII码是0x61,在unicode码是ox0061,都对应97.因此Unicode码兼容ASCII码. UTF-8编码介绍 UTF-8是在互联网上使用最广的一种Unicode的实现方式(改进) UTF-8是一种变长的编码方式。它可以使用1-6个字节表示一个符号,根据不同的符号而变化字节长度 使用大小可变的编码字母占1个字节,汉字占3个字节 6、布尔类型 布尔类型也叫boolean类型,在java中booolean类型数据只允许取值true和false,无null,同时不能使用其他字符代替true或false boolean类型占1个字节,boolean类型适于逻辑运算,一般用于程序流程控制 publicclasstest{publicstaticvoidmain(String[]args){booleanvar=true;if(var==true){System.out.println("ThisisTrue.");}else{System.out.println("ThisisFalse");}}}7、基本数据类型转换 当java程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数据类型,这个就是自动类型转换。 数据类型按精度(容量)大小排序为 inta='a';double=80;1>有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算 2>当我们把精度(容量)大的数据类型赋值给精度(容量)小的数据类型时,就会报错,反之就会进行自动类型转换 3>(byte,short)和char之间不会相互自动转换 4>byte,short,char他们三者可以计算,在计算时首先转换为int类型 5>boolean不参与转换 6>自动提升原则:表达式结果的类型自动提升为操作数中最大的类型 //代码示例1publicclasstype_change{publicstaticvoidmain(String[]args){bytea=10;intb=580;doublec=1314.20;doubleres=a+b+c;System.out.println(res);}}//代码示例2publicclasstype_change{publicstaticvoidmain(String[]args){doublec=1314;System.out.println(c);}}//代码示例3publicclasstype_change{publicstaticvoidmain(String[]args){bytea=13;shortb=200;charc='a';intres=a+b+c;System.out.println(res);}}8、强制类型转换 自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转换符(),但可能造成精度降低或溢出。 publicclasstype_change{publicstaticvoidmain(String[]args){inta=9527;byteres=(byte)a;System.out.println(res);}}上图的res结果为55,int类型的9527转为二进制为:00000000000000000010010100110111,因为byte为一个字节,所以只会保留上述二进制中的最后8位,即00110111=55,这种现象称为精度降低 强制类型转换细节说明 1>当进行转换的数据精度从大——>小,就需要使用到强制转换 2>强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级 3>char类型可以保存int的常量值,但不能保存int的变量值(byte同理),需要强转,因为变量的大小之前是固定好了的 4>byte和short、char类型在进行运算时,当做int类型处理 5>bytea=100;在给变量a赋值的时候,首先会判断100在不在byte的范围内,如果在的话则就赋值,不在则报错。 #案例演示1publicclasstype_change{publicstaticvoidmain(String[]args){intres=(int)10*3.5;//会报错intres=(int)(10*3.5);System.out.println(res);}}//案例演示2publicclasstype_change{publicstaticvoidmain(String[]args){inta=97;charb=97;//char可以保存int的常量值charres=(char)a;//如果保存int的变量值则需要强转System.out.println(res);//打印的是97对应的字母}}//案例演示3publicclasstype_change{publicstaticvoidmain(String[]args){bytea=97;shortb=97;charc=97;intres=a+b+c;System.out.println(res);//结果:291}}基本数据类型和String类型的转换 在程序开发中,我们经常需要将基本数据类型转成String类型。或者将String类型转成基本数据类型。 基本类型转String类型语法:将基本类型的值+""即可 publicclassHelloWorld{publicstaticvoidmain(String[]args){inta=9527;Stringstr=a+"";System.out.println(str);//9527System.out.println(str+1);//95271}}String类型转基本数据类型 语法:通过基本类型的包装类调用parseXX方法即可 publicclassHelloWorld{publicstaticvoidmain(String[]args){Stringstr="88";inta=Integer.parseInt(str);byteb=Byte.parseByte(str);shortc=Short.parseShort(str);longd=Long.parseLong(str);floate=Float.parseFloat(str);doublef=Double.parseDouble(str);booleang=Boolean.parseBoolean("true");System.out.println(a+1);System.out.println(b+1);System.out.println(c+1);System.out.println(d+1);System.out.println(e);System.out.println(f);System.out.println(g);}}注意事项 在将String类型转成基本数据类型时,要确保String类型能够转成有效的数据,比如我们可以把“123",转成一个整数,但是不能把"hello”转成一个整数,如果格式不正确,就会抛出异常,程序就会终止。 publicclasstest{publicstaticvoidmain(String[]args){Stringname="赵大大";shortage=22;floatgrade=99.99F;chargender='男';Stringhobby="女";System.out.println("姓名\t年龄\t成绩\t性别\t爱好\n"+name+"\t"+age+"\t"+grade+"\t"+gender+"\t"+hobby);}}五、运算符 运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。 算术运算符、赋值运算符、关系运算符[比较运算符]、逻辑运算符、位运算符(需要二进制基础)、三元运算符 1、算术运算符 算术运算符是对数值类型的变量进行运算的,在Java程序中使用的非常多。 2>当对一个数取模时,可以等价a%b=a-a/b*b,这样我们可以看到取模的一个本质运算。(a/b是java中的除法特点) 3>当自增作为一个独立语言使用时,不管是++i、还是i++都是一样的,等价于i=i+1 4>当自增作为一个表达式使用时:j=++i等价i=i+1、j=i 5>当自增作为一个表达式使用时:j=i++等价j=i、i=i+1 算术运算符练习题 publicclassrun{publicstaticvoidmain(String[]args){inti=1;i=i++;//规则使用临时变量:(1)temp=i、(2)i=i+1、(3)i=tempSystem.out.println(i);//打印结果:1intk=1;k=++k;//规则使用临时变量:(1)k=k+1、(2)temp=k、(3)k=tempSystem.out.println(k);//打印结果:2}}//定义一个变量保存华氏温度,华氏温度转换摄氏温度的公式为:5/9*(华氏温度-100),请求出华氏温度对应的摄氏温度。[234.5]publicclasstest{publicstaticvoidmain(String[]args){doublehuashi=234.5;doublesheshi=5.0/9*(huashi-100);//注意这里必须是5.0,不然在java里5/9=0的System.out.println(sheshi);}}(int)(Math.random()*100)+1;//生成1个1-100的随机数Math.random()方法可以生成[0,1)之间的数字,如果用这个数字乘以3就是一个从[0,3)之间的数字2、关系运算符 关系运算符也叫比较运算符,关系运算符的结果都是boolean型,也就是要么是true,要么是false 关系表达式经常用在if结构的条件中或循环结构的条件中 publicclassHelloWorld{publicstaticvoidmain(String[]args){intnumber_first=10;intnumber_second=20;System.out.println(number_first==number_second);//falseSystem.out.println(number_first!=number_second);//trueSystem.out.println(number_first 2>关系运算符组成的表达式,我们称为关系表达式:a>b 3>比较运算符"=="不能误写成"=","=="为等于。"="为赋值 3、逻辑运算符 用于连接多个条件(多个关系表达式),最终的结果也是一个boolean值。 逻辑运算符一览 短路与:&& 短路或:|| 逻辑与:& 逻辑或:| 取反:! 逻辑异或:^ a&b:&叫逻辑与,当a和b同时为true,则结果为true,否则为false a&&b:&&叫短路与,当a和b同时为true,则结果为true,否则为false alb:|叫逻辑或,当a和b,有一个为true,则结果为true,否则为false a||b:叫短路或,当a和b,有一个为true,则结果为true,否则为false !a:叫取反,或者非运算。当a为true,则结果为false;当a为false,结果为true a^b:叫逻辑异或,当a和b不同时,则结果为true,否则为false publicclasstest{publicstaticvoidmain(String[]args){intnumber_first=10;intnumber_second=20;System.out.println(!(number_first &&短路与:如果第一个条件为false,则第二个条件不会执行判断,最终结果就是false,效率高 &逻辑与:不管第一个条件是否为false,第二个条件都要判断,效率低 开发中,我们基本使用&& publicclasstest{publicstaticvoidmain(String[]args){intnumber_first=10;intnumber_second=20;if(number_first<5&&++number_second>15){System.out.println("条件为真");}System.out.println("number_first="+number_first+"number_second="+number_second);//number_first=10number_second=20}}如上图,因为number_first<5为假,所以++number_second就不会执行,如果为逻辑与&的话,就会执行++number_second了 |和||使用区别 ||短路或:如果第一个条件为true,则第二个条件不会执行判断,最终结果就为true,效率高 |逻辑或:不管第一个条件是否为true,第二个条件都要判断,效率低 开发中,我们基本使用|| publicclasstest{publicstaticvoidmain(String[]args){intnumber_first=10;intnumber_second=20;if(number_first<15||++number_second>30){System.out.println("条件为真");}System.out.println("number_first="+number_first+"number_second="+number_second);//number_first=10number_second=20}}如上图,因为number_first<15为真,所以++number_second就不会执行,如果为逻辑或|的话,就会执行++number_second了 逻辑运算符练习题 注意:x++==6,因为是后++,所以是先判断x==6,再进行自增,x++==6是一个表达式 所以答案如下:6,6|6,5|11,6|11,5 注意:(y=true)是一个赋值语句,&&判断的是赋值完之后的y的值 所以答案为50 4、赋值运算符 赋值运算符就是将某个运算后的值,赋给指定的变量 基本赋值运算符:inta=10 复合赋值运算符:+=、-=、*=、/=、%= a+=b:[等价a=a+b;] a-=b:[等价a=a-b;] 1>运算顺序从右往左intnum=a+b+c;,先计算a+b+c的值再赋值给num变量 2>赋值运算符的左边只能是变量,右边可以是变量、表达式、常量值 intnum=20、intnum2=78*34-10、intnum3=a 3>复合赋值运算符等价于下面的效果 比如:a+=3:等价于a=a+3其他类推 4>复合赋值运算符会自动进行类型的强制转换 5、三元运算符 基本语法 条件表达式?表达式1:表达式2;运算规则 1、如果条件表达式为true,运算后的结果是表达式1 2、如果条件表达式为false,运算后的结果是表达式2 使用细节 1、表达式1和表达式2要为可以赋给接收变量的类型(或可以自动转换) 2、三元运算符可以转成ifelse语句 publicclasstest{publicstaticvoidmain(String[]args){intnum_first=1;intnum_second=20;intresult=num_second>num_first13.14:5.20;//会报错intresult=num_second>num_first(int)13.14:(int)5.20;//会损失精度doubleresult=num_second>num_first13.14:5.20;//niceSystem.out.println(result);}}6、运算符优先级 运算符有不同的优先级,所谓优先级就是表达式运算中的运算顺序 如下表,上一行运算符总优先于下一行。只有单目运算符、赋值运算符是从右向左运算的 7、标识符规则与规范 标识符概念:Java对各种变量、方法和类等命名时使用的字符序列称为标识符 凡是自己可以起名字的地方都叫标识符intnumber_first=90;中的num_first就是标识符 标识符的命名规则(必须遵守) 1.由26个英文字母大小写、0-9、_或$组成 2、数字不可以开头(int3ab=1;是错误) 3、不可以使用关键字和保留字,但能包含关键字和保留字 4、Java中严格区分大小写,长度无限制。intabc与intAbc是两个变量 5、标识符不能包含空格。(intab=90;是错误的) 标识符的命名规范(更加专业) 1、包名:多单词组成时所有字母都小写:aaa.bbb.ccc比如com.zrh.crm 2、类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz【大驼峰】比如:TankShotGame 3、变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZz【小驼峰,简称驼峰法】比如:tankShotGame 4、常量名:所有字母都大写,多单词时每个单词用下划线连接:XXX_YYY_ZZZ比如:定义一个所得税率TAX_RATE 8、关键字与保留字 关键字:被Java语言赋予了特殊含义,用做专门用途的字符串(单词),特点:关键字中所有字母都为小写 Java保留字:现有Java版本尚未使用,但以后版本可能会作为关键字使用 自己命名标识符时要避免使用这些保留字byValue、cast、future、generic、inner、operator、outer、rest、var、goto、const 六、键盘输入 七、进制 对于整数,有四种表示方式: 二进制:0,1,满2进1,以0b或0B开头 十进制:0-9,满10进1 八进制:0-7,满8进1,以数字0开头表示。 十六进制:0-9及A(10)-F(15),满16进1,以0x或0X开头表示,此处的AF不区分大小写。 1、进制转换 二进制转十进制规则:从最低位(右边)开始,将每个位上的数提取出来,乘以2的(位数-1)次方,然后求和 0b1011=1*2^0+1*2^1+0*2^2+1*2^3=11 八进制转十进制:从最低位(右边)开始,将每个位上的数提取出来,乘以8的(位数-1)次方,然后求和 0234=4*8^0+3*8^1+2*8^2=156 十六进制转十进制规则:从最低位(右边)开始,将每个位上的数提取出来,乘以16的(位数-1)次方,然后求和 0X23A=10*16^0+3*16^1+2*16^2=570 十进制转二进制规则:将该数不断除以2,直到商为0为止,然后将每步得到的余数倒过来,就是对应的二进制 158=158/2=79……0、79/2=39……1、39/2=19……1、19/2=9……1、9/2=4……1、4/2=2……0、2/2=1……0;所以158=ob10011110 十进制转八进制规则:将该数不断除以8,直到商为0为止,然后将每步得到的余数倒过来,就是对应的八进制 131=131/8=16……3、16/8=2……0;所以131=0203 十进制转十六进制规则:将该数不断除以16,直到商为0为止,然后将每步得到的余数倒过来,就是对应的十六进制 237=237/16=14……13;所以237=0XED 二进制转八进制规则:从低位开始,将二进制数每三位一组,转成对应的八进制数即可 0b11010110=011、010、110=3、2、6=0326 二进制转十六进制规则:从低位开始,将二进制数每四位一组,转成对应的十六进制数即可 0b11010110=1101、0110=13、6=0XD6 八进制转二进制规则:将八进制数每1位,转成对应的一个3位的二进制数即可 0237=2、3、7=010、011、111=ob10011111 十六进制转二进制规则:将十六进制数每1位,转成对应的4位的一个二进制数即可 0X23B=2、3、B=0010、0011、1011=ob1000111011 2、原码反码补码 对于有符号的而言: 1>二进制的最高位是符号位:0表示正数、1表示负数 2>正数的原码,反码,补码都一样(三码合一) 3>负数的反码=它的原码符号位不变,其它位取反(0变1、1变0) 4>负数的补码=它的反码+1,负数的反码=负数的补码-1 5>0的反码,补码都是0 6>java没有无符号数,换言之,java中的数都是有符号的 7>在计算机运算的时候,都是以补码的方式来运算的 8>当我们看运算结果的时候,要看他的原码 #例如:int2int2的源码=00000000000000000000000000000010因为2是正数,所以2的原码、补码、反码都一样,三码合一#例如:int-2int-2的源码=10000000000000000000000000000010int-2的反码=11111111111111111111111111111101int-2的补码=111111111111111111111111111111103、位运算符 java中有7个位运算:&、|、^、~、>>、<<、>>> 按位与&:两位全为1,结果为1,否则为0 按位或|:两位有一个为1,结果为1,否则为0 按位异或^:两位一个为0,一个为1,结果为1,否则为0 按位取反~:0变1,1变0 算术右移>>:低位溢出,符号位不变,并用符号位补溢出的高位 算术左移<<:符号位不变,低位补0 逻辑右移>>>:也叫无符号右移,低位溢出,高位补0 八、程序流程控制 在程序中,程序运行的流程控制决定程序是如何执行的,是我们必须掌握的,主要有三大流程控制语句:顺序控制、分支控制、循环控制 顺序控制:程序从上到下逐行地执行,中间没有任何判断和跳转 1、分支控制 让程序有选择的的执行,分支控制有三种 //1、单分支ifpublicclassHelloWorld{publicstaticvoidmain(String[]args){intage=20;if(age>18){System.out.println("你的年龄大于18,请为自己的行为负责!");}}}//2、双分支if-elsepublicclasstest{publicstaticvoidmain(String[]args){intyearNum=2020;if((yearNum%4==0&&yearNum%100!=0)||yearNum%400==0){System.out.print("此年份是闰年");}else{System.out.print("此年份不是闰年");}}}//3、多分支if-elseif-...-elsepublicclasstest{publicstaticvoidmain(String[]args){intgrade=95;if(grade>=100){System.out.print("信用极好");}elseif(80 2>如果有else,如果所有的条件表达式都不成立,则默认执行else代码块 2、嵌套分支 在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层分支外面的分支结构称为外层分支,建议不要超过3层,可读性不好 publicclasstest{publicstaticvoidmain(String[]args){doublescore=9.5;if(score>8.0){chargender='女';//myScanner.next().charAt(0)本质是将字符串的第一个字符转成charif(gender=='男'){System.out.print("恭喜你进入男子组决赛");}elseif(gender=='女'){System.out.print("恭喜你进入女子组决赛");}else{System.out.print("性别错误,无法参加决赛");}}else{System.out.println("Sorry,你已被淘汰");}}}3、switch分支结构 2>表达式对应一个值 3>case常量1:当表达式的值等于常量1,就执行语句块1 4>break表示退出swtich 5>如果和case常量1匹配,就执行语句块1,如果没有匹配,就继续匹配case常量2 6>如果一个都没有匹配上,执行default switch结构细节 1>表达式数据类型,应和case后的常量类型一致,或者是可以自动转成可以相互比较的类型,比如输入的是字符,常量是int就可以,因为char可以自动转为int 2>switch中的表达式返回值必须是:(byte、short、int、char、enum[枚举]、String) publicclasstest{publicstaticvoidmain(String[]args){doublec=1.1;switch(c){//错误,后面类型不符合规定case1.1://错误,后面类型不符合规定System.out.println("ok3");break;}}}3>case子句中的值必须是常量或常量表达式,而不能是变量 4>default子句是可选的,当没有匹配的case时,执行default 5>break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有写break,程序会顺序执行到switch结尾,除非遇到break; //根据用于指定月份,打印该月份所属的季节//3.4.5春季、6.7.8夏季、9.10.11秋季、12.1.2冬季//[必须使用Switch且必须使用穿透]publicclasstest{publicstaticvoidmain(String[]args){intc=8;switch(c){case3:case4:case5:System.out.print("春季");break;case6:case7:case8:System.out.print("夏季");break;case9:case10:case11:System.out.print("秋季");break;case12:case1:case2:System.out.print("冬季");break;default:System.out.print("输入月份有误");}}}switch和if的选择 1>如果判断的具体数值不多,而且符合byte、short、int、char、enum[枚举]、String这6种类型。虽然两个语句都可以使用,建议使用swtich语句 2>其他情况:对区间判断,对结果为boolean类型判断,使用if,if的使用范围更广 4、循环控制-for循环 1>for关键字,表示循环控制 2>for有四要素①循环变量初始化②循环条件③循环操作④循环变量迭代 3>循环操作,这里可以有多条语句,也就是我们要循环执行的代码 4>如果循环操作(语句)只有一条语句,可以省略{},建议不要省略 for循环细节 1>循环条件是返回一个布尔值的表达式 2>for(;循环判断条件;)中的循环变量初始化和变量迭代可以写到其它地方,但是两边的分号不能省略 #循环变量初始化如果写到for外面,那么之后还可以使用循环变量的值,如果循环变量写到for循环里,那么就只能在for循环里面使用publicclasstest{publicstaticvoidmain(String[]args){inti=1;//循环变量初始化写到外面for(;i<10;){System.out.println("Hello,World"+i);i++;}System.out.print(i);//for循环外还可以调用i变量}}循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开,循环变量迭代也可以有多条变量迭代语句,中间用逗号隔开 publicclasstest{publicstaticvoidmain(String[]args){for(inti=1,j=0;i<10;i+=2,j++){System.out.println("i="+i+"j="+j);}}}for循环练习 //打印1~100之间所有是9的倍数的整数,统计个数及总和.publicclasstest{publicstaticvoidmain(String[]args){System.out.println("符合条件的整数如下:");inti=1;intcount=0;intsum=0;for(;i<=100;i++){if(i%9==0){count++;sum+=i;System.out.print(i+"\t");}}System.out.print("\n统计个数为:"+count+"\n总和为:"+sum);}}for(;;;){}//表示无限循环,也叫死循环,可以配合break一起使用5、循环控制-while循环 while循环也有四要素,只不过四要素的位置与for循环不一样而已 细节说明 2>while循环是先判断再执行语句 publicclasstest{publicstaticvoidmain(String[]args){//打印1-100之间所有能被3整除的数,使用whileintnumber=1;while(number<=100){switch(number%3){case0:System.out.print(number+"\t");}number++;}}}6、do…while循环 1>dowhile是关键字 2>也有循环四要素,只是位置不一样 3>先执行,再判断,也就是说,一定会至少执行一次 4>最后有一个分号 2>do...while循环是先执行,再判断,因此至少执行一次 7、多重循环 多重循环也叫嵌套循环,将一个循环放在另一个循环体内,就形成了嵌套循环。其中for、while、do..while均可以作为外层循环和内层循环。【建议一般使用两层,最多不要超过3层,否则,代码的可读性很差】 实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为false时,才会完全跳出内层循环,才可结束外层的当次循环,开始下一次的循环 设外层循环次数为m次,内层为n次,则内层循环体实际上需要执行m*n次 8、化繁为简、先死后活 统计3个班成绩情况,每个班有5名同学,求出各个班的平均分和所有班级的平均分,并统计三个班及格人数(学生的成绩从键盘输入) 1>化繁为简 ①要统计三个班的成绩情况,可以先统计一个班的成绩情况,因为每个班有5个学生,每个学生的成绩都是键盘输入,所以可以设置for循环输入5次 ②成绩输入完后计算平均分,可以定义一个doublesum把5名学生的成绩进行累和,然后除以人数就可以得到一个班平均值 ③一个班处理完了,可以处理三个班,一个班的代码框架完成后,可以在代码框架外加一个循环3次的for循环,这样就可以得到3个班的成绩情况 ④要计算三个班的平均分,可以定义一个变量doubletotalScore来累和每个班成绩,然后除以三个班的人数就是三个班的平均值 ⑤统计三个班的及格人数,可以设置一个变量intcount,如果输入学生的成绩>=60,那么就对count++,最后打印count即可 2>先死后活 ①上面所说每班5个学生,就做了5次的for循环,可以将5设置成变量 ②上面所说3个班级,就做了3次的for循环,可以将3设置成变量 先死后活的含义就是先将内容写死,然后通过变量将内容替换,这样就可以修改变量的内容达到灵活的目的 9、跳转控制语句break break语句用于终止某个语句块的执行,一般使用在switch或者循环[for、while、do-while]中 break语句出现在多层嵌套的语句块中时,可以通过标签指明要终止的是哪一层语句块 1>break语句可以指定退出哪层 2>label1是标签,名字由程序员指定 3>break后指定到哪个label就退出到哪里 4>在实际的开发中,尽量不要使用标签. 5>如果没有指定break,默认退出最近的循环体 上图代码将breaklabel1取消注释以后,结果如下: 注意:判断两个字符安川是否相等需要用到String下的equals方法 "丁真".equals(username)10、跳转控制语句continue 1>continue语句用于结束本次循环,继续执行下一次循环 2>contimue语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环﹐这个和前面的标签的使用的规则一样 publicclasstest{publicstaticvoidmain(String[]args){label1:for(inti=1;i<=3;i++){label2:for(intk=1;k<=3;k++){if(k==2){continue;//等价于continuelabel2;结果为打印三次k=1、k=2//continuelabel1;结果为打印三次k=1}System.out.println("k="+k);}}}}11、跳转控制语句return return使用在方法上,表示跳出所在的方法,在讲解方法的时候,会详细的介绍,这里我们简单的提一下 注意:如果return写在main方法,表示退出程序 publicclasstest{publicstaticvoidmain(String[]args){inti=1;do{if(i==2){return;}System.out.println("i="+i);i++;}while(i<=3);System.out.println("循环结束");//return之后这句话就不会被执行}}12、程序控制结构作业 //计算1-1/2+1/3-1/4......1/100的和publicclasstest{publicstaticvoidmain(String[]args){doublesum=0.0;for(inti=1;i<=100;i++){if(i%2==0){sum-=(1.0/i);//注意1.0,注意java中/的陷阱}else{sum+=(1.0/i);}}System.out.println("和="+sum);}}//求1+(1+2)+(1+2+3)+(1+2+3+4)+...+(1+2+...+100)的结果//第一种publicclasstest{publicstaticvoidmain(String[]args){intsum=0;intres=0;for(inti=1;i<=100;i++){sum+=i;res+=sum;}System.out.println("result="+res);}}//第二种publicclasstest{publicstaticvoidmain(String[]args){intsum=0;for(inti=1;i<=100;i++){for(intk=1;k<=i;k++){sum+=k;}}System.out.println("result="+res);}}九、数组 数组可以存放多个同一类型的数据,数组也是一种数据类型,是引用类型,即:数组就是一组数据 publicclasstest{publicstaticvoidmain(String[]args){intarr[]=newint[5];//int表示数组为int类型//arr表示数组的名称//[]表示数据//newint[5]表示在内存中创建数组,数组可以存放5个元素System.out.print(arr.length);//arr.length表示arr数组的长度arr[0]=520;//给数组的第一个元素赋值,数组的索引是从0开始的System.out.print(arr[0]);}}1、数组的使用方式 使用情况:知道数组有多少元素且知道元素具体的值 publicclasstest{publicstaticvoidmain(String[]args){//int[]arr;也可以intarr[]={1,2,3};//以上一句代码相当于//intarr[]=newint[3];//arr[0]=1;//arr[1]=2;//arr[2]=3;}}注意:Stringstrs[]=newString[]{"a","b","c"};//这样是正确的Stringstrs[]=newString[3]{"a","b","c"};//这样是错误的2、数组使用注意事项和细节 1>数组是多个相同类型数据的组合(自动类型转换的也可以放在同一个数组里),实现对这些数据的统一管理 2>数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用 3>数组创建后,如果没有赋值,有默认值 int0、short0、byte0、long0、float0.0、double0.0、char/u0000、booleanfalse、Stringnull 5>数组的下标是从0开始的 6>数组下标必须在指定范围内使用,否则报:下标越界异常,比如 7>数组属引用类型,数组型数据是对象(object) //创建一个char类型的26个元素的数组,分别放置'A‘-'Z',使用for循环访问所有元素并打印出来publicclasstest{publicstaticvoidmain(String[]args){chararray[]=newchar[26];for(inti=0;i<=25;i++){array[i]=(char)('A'+i);//array[]是数组类型,array[1]是char类型System.out.print(array[i]+"");}}}3、赋值机制与数组拷贝 在引用传递的赋值机制下,修改array_second元素的值是会影响到array_first元素的值的,因为array_firs和array_second指向的是同一个内存地址 如果想要拷贝一个相互不影响的数组,那么就需要用拷贝的赋值机制对数组进行拷贝,操作如下: 新建一个数组,数组的长度与需要拷贝的数组相同,再将需要拷贝的数组元素的值一一赋给新建数组的元素的值即可 publicclasstest{publicstaticvoidmain(String[]args){intarray_first[]={1,3,5,7,9};intarray_second[]=newint[array_first.length];for(inti=0;i 要求:把数组的元素内容反转 //根据规律反转publicclassTest{publicstaticvoidmain(String[]args){intarrary_first[]={1,2,3,4,5,6};inttemp=0;for(inti=0;i //实现动态的给数组添加元素效果,实现对数组扩容//用户可以通过如下方法来决定是否继续添加:添加成功,是否继续y/nimportjava.util.Scanner;publicclasstest{publicstaticvoidmain(String[]args){intarray[]={1,2,3};ScannermyScanner=newScanner(System.in);System.out.println("原始数组内容如下:");for(inti=0;i 7、排序 排序是将多个数据,依指定的顺序进行排列的过程 排序的分类: 内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序。包括(交换式排序法、选择式排序法和插入式排序法) 外部排序法:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。包括(合并排序法和直接合并排序法) 冒泡排序法 冒泡排序(BubbleSoting)的基本思想是:通过对待排序序列从后向前(从下标较大的元素开始〉,依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就像水底下的气泡一样逐渐向上冒。 将五个无序:24,69,80,57,13使用冒泡排序法将其排成一个从小到大的有序数列 publicclasstest{publicstaticvoidmain(String[]args){intarray[]={24,69,80,57,13};inttemp=0;inttime=0;for(intk=1;k 1>从定义形式上看:int[][]name或者intname[][] 2>二维数组的每一个元素是一个一维数组 二维数组的每个元素是一维数组,所以如果需要得到每个一维数组的值还需要再次遍历 访问第(i+1)个一维数组的第j+1个值:arr[i][j]; arr[i]表示二维数组的第i+1个元素比如:arr[0]表示二维数组的第一个元素 arr.length表示二维数组的长度、arr[i].length得到对应的每个一维数组的长度 1、二维数组在内存中的存在形式 2、二维数组的使用方式 创建二维数组,二维数组中有3个一维数组,但是每个一维数组还没有开辟数据空间 publicclasstest{publicstaticvoidmain(String[]args){intarray[][]=newint[3][];//没有创建一维数组元素的个数for(inti=0;i publicclasstest{publicstaticvoidmain(String[]args){intarray[][]=new{{1,2,3},{1,2},{1}};//定义了一个二维数组//二维数组有三个元素,每个元素都是一维数组//第一个一维数组有3个元素、第二个有2个元素、最后一个有一个元素}}3、二维数组使用细节和注意事项 3>二维数组实际上是由多个一维数组组成的,它的各个一维数组的长度可以相同,也可以不相同 比如:map[][]是一个二维数组 intmap[][]={{1,2},{3,4,5}} map[0]是一个含有两个元素的一维数组,map[1]是一个含有三个元素的一维数组构成,我们也称为列数不等的二维数组 int[]x,y[]//表示x是int类型一维数组,y是int类型的二维数组4、二维数组练习 //已知有个升序的数组,要求插入一个元素,该数组顺序依然是升序//比如:[10,12,45,90],添加23后,数组为[10,12,23,45,90]importjava.util.Scanner;publicclasstest{publicstaticvoidmain(String[]args){ScannermyScanner=newScanner(System.in);System.out.print("请输入插入的数:");intval=myScanner.nextInt();inttemp=0;intarray[]={10,12,45,90,99,102,129,168};intarray_temp[]=newint[array.length+1];for(inti=0;i 1、类与对象 类是抽象的,概念的,代表一类事物,比如人类、猫类、狗类...... 类是数据类型;对象是具体的、实际的,代表一个具体事物,即是实例 类是对象的模板,对象是类的一个个体,对应一个实例 publicclasstest{publicstaticvoidmain(String[]args){Cathk=newCat();//创建一个对象hk.name="flower";hk.age=2;hk.color="white";Catxk=hk;System.out.print("这只猫的信息为:"+hk.name+""+hk.age+""+hk.color);}}classCat{//定义Cat类Stringname;intage;Stringcolor;}2、对象在内存中的存在形式 非基本数据类型都存放在方法区的常量池中,基本数据类型就直接保存在类所在的内存地址里 类和对象的内存分配机制,Java内存的结构分析 1>栈:一般存放基本数据类型(局部变量) 2>堆:存放对象(Cathk,数组等) 3>方法区:常量池(常量,比如字符串),类加载信息 注意:如果xk=null;这代表xk置空,置空之后xk与创建的对象就失去了链接 3、属性 从概念或叫法上看:成员变量=属性=field(字段)(即成员变量是用来表示属性的,本文中统一叫属性) classCat{//定义Cat类Stringname;//成员变量、属性、字段intage;Stringcolor;String[]hosts;//属性可以是基本数据类型,也可以是引用类型(对象,数组)}注意事项和细节说明 1>属性的定义语法同变量,示例:访问修饰符属性类型属性名; 简单的介绍访问修饰符:控制属性的访问范围 有四种访问修饰符public、proctected、默认、private 2>属性的定义类型可以为任意类型,包含基本类型或引用类型 3>属性如果不赋值,有默认值,规则和数组一致 具体说:int0、short0、byte0、long0、float0.0、double0.0、char/u0000、booleanfalse、Stringnull publicclasstest{publicstaticvoidmain(String[]args){Cathk=newCat();//hk是对象名,也叫对象引用//newCat()为创建的对象空间,是真正的对象,对象名只是指向了这个对象空间而已}}创建对象及访问属性 1>先加载Cat类信息(属性和方法信息,只会加载一次) 2>在堆中分配空间,进行默认初始化(int0、double0.0.....) 3>把地址赋给hk,hk就指向对象 4>进行指定初始化,比如hk.name="flower"hk.age=2 4、方法 1>方法写好后,如果不去调用(使用),不会输出 2>先创建对象,然后调用方法即可 publicclasstest{publicstaticvoidmain(String[]args){Personhk=newPerson();//创建一个对象hk.speak();//调用speak方法}}classPerson{//定义Cat类Stringname;intage;//1、public表示方法公开//2、void表示方法没有返回值//3、speak()中speak为方法名,()为形参列表//4、{}方法体,可以写我们要执行的代码体publicvoidspeak(){System.out.print("Thisisagoodman.");}}方法快速入门 publicclasstest{publicstaticvoidmain(String[]args){Personhk=newPerson();//创建一个对象hk.cal(500);//调用cal方法,同时传入参数,即n=500intresult=hk.getSum(10,20);System.out.println(result);}}classPerson{//定义Cat类Stringname;intage;//定义speak方法publicvoidspeak(){System.out.println("Thisisagoodman.");}//定义cal方法publicvoidcal(intn){//表示当前有一个形参n(形式参数),可以接受用户输入intsum=0;for(inti=1;i<=n;i++){sum+=i;}System.out.println("1+2+...+"+n+"="+sum);}//定义getSum方法//1、piblic后的int表示方法执行后,返回一个int值//2、(intnum1,intnum2)表示形参列表,可以接受用户传入两个参数//3、return表示将结果返回publicintgetSum(intnum1,intnum2){intres=num1+num2;returnres;}}方法的调用机制 这里使用getSum方法进行演示 方法调用总结 1>当程序执行到方法时,就会开辟一个独立的空间(栈空间) 2>当方法执行完毕,或者执行到return语句时,就会返回相应的结果到调用方法的地方 3>返回后,栈空间被垃圾回收机制回收,然后继续执行方法后面的代码 4>当main方法(栈)执行完毕,整个程序退出 5、成员方法的定义及细节 1>形参列表:表示成员方法输入的参数cal(intn)、getSum(intnum1,intnum2) 2>返回数据类型:表示成员方法输出,void表示没有返回值 3>方法主体:表示为了实现某一功能代码块 4>return语句不是必须的 成员方法的好处:提高代码的复用性、可以将实现的细节封装起来,然后供其他用户来调用即可 方法细节及注意事项 返回数据类型 1>一个方法最多有一个返回值,如果需要返回多个值可以返回数组 2>返回类型可以为任意类型,包含基本类型或引用类型(数组,对象) publicclasstest{publicstaticvoidmain(String[]args){myToolstools=newmyTools();//创建对象int[]result=tools.printArr(20,10);System.out.println("result[0]="+result[0]);System.out.println("result[1]="+result[1]);}}classmyTools{publicint[]printArr(intnum1,intnum2){//返回数据类型为数组int[]res=newint[2];//创建数组res[0]=num1+num2;res[1]=num1-num2;returnres;//返回数组}}3>如果方法要求有返回数据类型,则方法体中最后的执行语句必须为return值,而且要求返回值类型必须和return的值类型一致或兼容 4>如果方法是void,则方法体中可以没有retun语句,或者只写return;(即return后没有返回值) 方法名 遵循驼峰命名法,最好见名知义,表达出该功能的意思即可,比如得到两个数的和getSum,开发中按照规范 形参列表 1>一个方法可以有0个参数,也可以有多个参数,中间用逗号隔开,比如:getSum(intn1,intn2) 2>参数类型可以为任意类型,包含基本类型或引用类型,比如:printArr(int[][]map) 3>调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型的参数 4>方法定义时的参数称为形式参数,简称形参;方法调用时的传入参数称为实际参数,简称实参,实参和形参的类型要一致或兼容、个数、顺序必须一致 方法体 方法体里面写完成功能的具体的语句 可以为输入、输出、变量、运算、分支、循环、方法调用,但里面不能再定义方法! 即:方法不能嵌套定义,(只是不能嵌套定义,但是方法体里可以调用其他方法) 6、方法调用细节说明 1>同一个类中的方法调用:直接调用即可 案例演示:myTools类中的sayOk方法调用printArr方法 publicclasstest{publicstaticvoidmain(String[]args){myToolstools=newmyTools();//创建对象tools.sayOk(520);}}classmyTools{//定义printArr方法publicvoidprintArr(intnum){//无数据类型System.out.println("你输入的数字为="+num);}//定义sayOk方法publicvoidsayOk(intnum){System.out.println("sayOk方法已调用");printArr(num);//调用同一个类的printArr方法}}2>跨类中的方法A类调用B类方法:需要通过对象名调用,比如:对象名.方法名(参数); 案例演示:myTools类的sayHello方法调用herTools类的printArr方法 7、成员方法传参机制 1>基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参 publicclasstest{publicstaticvoidmain(String[]args){Mytoolstools=newMytools();intn=10;intm=20;tools.swap(n,m);System.out.print("main方法的:n="+n+"m="+m);//main方法的:n=10m=20}}classMytools{publicvoidswap(intn,intm){inttemp=n;n=m;m=temp;System.out.println("swap方法的:n="+n+"m="+m);//swap方法的:n=20m=10}}2>引用类型传递的是地址(传递也是值,但值是地址),可以通过形参的改变影响实参 8、克隆对象 编写一个方法copyPerson,可以复制一个Person对象,返回复制的对象,即克隆对象 注意:要求得到新对象和原来的对象是两个独立的对象,只是他们的属性相同 publicclasstest{publicstaticvoidmain(String[]args){Personp=newPerson();p.name="King";p.age=22;Mytoolstools=newMytools();Personp2=tools.copyPerson(p);System.out.println("P的属性为:"+"p.name="+p.name+"p.age="+p.age);System.out.println("P2的属性为:"+"p2.name="+p2.name+"p2.age="+p2.age);System.out.println(p==p2);//判断p与p2是否属于同一对象空间}}classPerson{Stringname;intage;}classMytools{//编写方法的思路//1、方法的返回类型Person,属于一个类(int是100的类)//2、方法的名字copyPerson//3、方法的形参是一个对象,对象又是Person类的实例,所以为PersonppublicPersoncopyPerson(Personp){Personp2=newPerson();p2.name=p.name;p2.age=p.age;returnp2;}}十二、递归 递归就是方法自己调用自己,每次调用时传入不同的变量 递归细节 1、执行一个方法时,就创建一个新的受保护的独立空间(栈空间) 2、方法的局部变量是独立的,不会相互影响,比如上图中的number变量 3、如果方法中使用的是引用类型变量(比如数组、对象),就会共享该引用类型的数据,那么局部变量之间就会受到影响 4、递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError 5、当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕(栈空间也就被回收) 十三、方法的重载 java中允许在同一个类中,定义多个同名的方法,但要求形参列表不一致 重载的好处:1、减轻了起名的麻烦2、减轻了记名的麻烦 publicclasstest{publicstaticvoidmain(String[]args){Mytoolstools=newMytools();System.out.println(tools.m(5));System.out.println(tools.m(10,50));tools.m("HK9527");}}classMytools{publicintm(intnum){returnnum*num;}publicintm(intnum1,intnum2){returnnum1*num2;}publicvoidm(Stringstr){System.out.print(str);}}注意事项和使用细节 1、方法名必须相同 2、形参列表必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求) 3、返回类型无要求,及相同与否都可以 4、在调用重载方法时,优先调用传入参数与方法定义参数的类型未发生类型转换的方法 十四、可变参数 java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法,就可以通过可变参数实现 访问修饰符返回类型方法名(数据类型...形参名){}1、可变参数的实参可以为0个或任意多个 2、可变参数的实参可以为数组 3、可变参数的本质就是数组 4、可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后 5、一个形参列表中只能出现一个可变参数 publicclasstest{publicstaticvoidmain(String[]args){Mytoolstools=newMytools();tools.showScore("HK9527",85,95,87,96,88);}}classMytools{publicvoidshowScore(Stringname,double...score){doublesum=0;for(inti=0;i 1、在java编程中,主要的变量就是属性(成员变量)和局部变量 2、我们说的局部变量一般是指在成员方法中定义的变量 3、java中作用域的分类 全局变量:也就是属性,作用域为整个类体 局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中 4、全局变量(属性)可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值 注意事项和细节使用 1、属性和局部变量可以重名,访问时遵循就近原则 publicclasstest{publicstaticvoidmain(String[]args){Mytoolstools=newMytools();tools.var();}}classMytools{Stringname="ZRH";//属性/全局变量publicvoidvar(){Stringname="KING";//局部变量System.out.println(name)//输出结果:KING}}2、在同一个作用域中,比如在同一个成员方法中,两个局部变量不能重名 3、属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁 局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。 4、作用域范围不同 全局变量/属性:可以被本类使用,或其他类使用(通过对象调用) 局部变量:只能在本类对应的方法中使用 publicclasstest{publicstaticvoidmain(String[]args){Mytoolstools=newMytools();tools.var();Histoolshtools=newHistools();htools.temp(tools);//其他类通过传入对象参数调用}}classMytools{Stringname="ZRH";//属性/全局变量publicvoidvar(){intage=10;//局部变量System.out.println(name);//在本类的方法中使用全局变量System.out.println(age);//只能在本类对应的方法中使用}}classHertools{publicvoidtemp(){Mytoolsvalue=newMytools();System.out.println(value.name);//其他类通过创建对象调用}}classHistools{publicvoidtemp(Mytoolstools){System.out.println(tools.name);//其他类通过传入对象参数调用}}5、修饰符不同 全局变量/属性可以加修饰符,局部变量不可以加修饰符 classMytools{publicStringname="ZRH";//这样写是正确的,属性/全局变量可以加修饰符publicvoidvar(){publicintage=10;//这样写是错误的,局部变量不可以加修饰符,会报错}}十六、构造器 构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化 [修饰符]方法名(形参列表){方法体;}它有几个特点: 1>方法名和类名相同 2>没有返回值 3>在创建对象时,系统会自动的调用该类的构造器完成对象的初始化 4>参数列表和成员方法一样的规则 5>构造器的调用,由系统完成 6>构造器的修饰符可以默认,也可以是public、protected、private publicclasstest{publicstaticvoidmain(String[]args){Mytoolstools=newMytools("Zrh");System.out.println(tools.name);//打印结果:Zrh}}classMytools{Stringname;//属性/全局变量Mytools(Stringtest_name){name=test_name;}}1、注意事项和使用细节 1>一个类可以定义多个不同的构造器,即构造器重载 比如:我们可以再给Mytools类定义一个构造器,用来创建对象的时候只指定人名,不需要指定年龄 publicclasstest{publicstaticvoidmain(String[]args){Mytoolsfirst_tools=newMytools("Zrh");//只指定姓名System.out.println(first_tools.name);//打印结果:ZrhMytoolssecond_tools=newMytools("Zrh",22);//指定姓名和年龄System.out.println(second_tools.name+""+second_tools.age);//打印结果:Zrh22}}classMytools{Stringname;//属性/全局变量intage;Mytools(Stringtest_name){name=test_name;}Mytools(Stringtest_name,inttest_age){//构造器重载name=test_name;age=test_age;}}2>构造器名和类名要相同 3>构造器没有返回值 4>构造器是完成对象的初始化,并不是创建对象 5>在创建对象时,系统自动调用该类的构造方法 6>如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器),使用javap指令反编译可以查看 7>一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,除非显式的定义一下(这点很重要) publicclasstest{publicstaticvoidmain(String[]args){Mytoolsfirst_tools=newMytools("Zrh");//只指定姓名Mytoolssecond_tools=newMytools();//只有显示定义了无参构造器才可以继续这样使用}}classMytools{Stringname;//属性/全局变量intage;Mytools(Stringtest_name){name=test_name;}Mytools(){//无参构造器}}2、创建对象流程分析 classPerson{//类Personintage=90;Stringname;Person(Stringn,inta){//构造器name=n;//给属性赋值age=a;//}}Personp=newPerson("小倩",20);3、流程分析(面试题) 1>加载Person类信息(Person.class),只会加载一次 2>在堆中分配空间(地址) 3>完成对象初始化 ①默认初始化age=0name=null ②显式初始化age=90,name=null ③构造器的初始化age=20,name=小倩 4>在对象在堆中的地址,返回给p(p是对象名,也可以理解成是对象的引用) 十七、this java虚拟机会给每个对象分配this用来代表当前对象 1、this的注意事项和使用细节 1>this关键字可以用来访问本类的属性、方法、构造器 2>this用于区分当前类的属性和局部变量 3>访问成员方法的语法:this.方法名(参数列表) 4>访问构造器语法:this(参数列表);注意只能在构造器中使用(即只能在构造器中访问另外一个构造器且必须放在第一条语句) publicclasstest{publicstaticvoidmain(String[]args){Mytoolstools=newMytools();}}classMytools{Stringname;intage;Mytools(){this("Zrh",22);//访问构造器语法必须放置在第一条语句System.out.println("Mytools()构造器被调用");}Mytools(Stringname,intage){System.out.println("Mytools(Stringname,intage)构造器被调用");}}5>this不能在类定义的外部使用,只能在类定义的方法中使用 6>this简单的说,哪个对象调用,this就代表哪个对象 2、匿名对象 匿名对象就是没有名字的对象,使用一次即会销毁 publicclasstemp{intcount=9;publicvoidcount1(){count=10;}publicstaticvoidmain(String[]args){newtemp().count1();//匿名对象存在于堆中,但是只能用一次}}3、练习题 设计类的成员变量,成员方法,可以电脑猜拳,电脑每次都会随机生成0、1、2 0表示石头、1表示剪刀、2表示布,并要可以显示输赢次数 importjava.util.Scanner;classgame{publicvoidfinger(){ScannerMyscanner=newScanner(System.in);inti=0;intj=0;do{System.out.println("请输入你的猜拳:(0=石头、1=剪刀、2=布、3=退出)");intres=Myscanner.nextInt();inttemp=(int)(Math.random()*3);if(res==3)break;if(temp-1==res||res-2==temp)i++;elsej++;System.out.println("电脑随机猜拳:"+temp+"\n你胜利的次数:"+i+"\t你失败的次数:"+j);}while(true);}}十八、IDEA的使用 1、编码设置 2、文件保存内容介绍 3、自动导入所需要的类 4、配置运行快捷键 5、生成构造器 6、查看一个类的层级关系ctrl+H 7、将光标放在一个方法上,输入ctrl+B,可以定位到方法的位置 8、创建对象时自动分配变量名 importjava.util.Scanner;publicclasstest{intage;Stringname;publicstaticvoidmain(String[]args){//newScanner(System.in).var然后回车Scannerscanner=newScanner(System.in);}}9、模板 10、去掉形参提示符 十九、包 包的本质实际上就是创建不同的文件夹/目录来保存类文件 包的三大作用 1、区分相同名字的类 2、当类很多时,可以很好的管理类 3、控制访问范围 快速入门 包的命名规则 只能包含数字、字母、下划线、小圆点,但不能用数字开头,不能是关键字或保留字 命名规范 一般是小写字母+小圆点一般是com.公司名.项目名.业务模块名 举例:com.sina.crm.user//用户模块com.sina.crm.order//订单模块com.sina.crm.utils//工具类注意事项和使用细节 2、import指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求 二十、访问修饰符 java提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问(范围) 1、公开级别:用public修饰,对外公开 2、受保护级别:用protected修饰,对子类和同一个包中的类公开 3、默认级别:没有修饰符号,向同一个包的类公开 4、私有级别:用private修饰,只有类本身可以访问,不对外公开 四种访问修饰符的访问范围 注意:子类可以访问父类的默认方法/属性的前提是在同一个包中 packagecom.first;publicclassA{publicintnum1=10;protectedintnum2=20;intnum3=30;privateintnum4=40;publicvoidAm(){System.out.println(num1+""+num2+""+num3+""+num4);}}packagecom.first;publicclassB{publicvoidBm(){Aa=newA();System.out.println(a.num1+""+a.num2+""+a.num3);}}packagecom.second;publicclassA{publicvoidAn(){com.first.Aa=newcom.first.A();System.out.println(a.num1);}}注意事项 1、修饰符可以用来修饰类中的属性,成员方法以及类 2、只有默认的和public才能修饰类!,并且遵循上述访问权限的特点 3、成员方法的访问规则和属性完全一样 二十一、封装介绍 1、封装的理解和好处 隐藏实现细节 可以对数据进行验证,保证安全合理 2、封装的实现步骤 将属性进行私有化private【使用户不能直接修改属性】 提供一个公共的(public)set方法,用于对属性判断并赋值 publicvoidsetXxx(类型参数名){//Xxx表示某个属性//加入数据验证的业务逻辑属性=参数名;}3、提供一个公共的(public)get方法,用于获取属性的值 public数据类型getXxx(){//可以加一些权限判断returnxx;}4、案例 请大家看一个小程序,不能随便查看人的姓名,年龄,工资等隐私,并对设置的年龄进行合理的验证 年龄合理就设置,否则给默认年龄18,必须在1-120 年龄,工资不能直接查看,name的长度在2-6字符之间 packagecom.encapsulation;publicclassShow{publicstaticvoidmain(String[]args){Personperson=newPerson();person.setName("HK9527");person.setAge(22);person.setSalary(9999.99);System.out.println(person.name);//这样会报错的!System.out.println(person.getName()+""+person.getAge()+""+person.getSalary());}}classPerson{privateStringname;privateintage;privatedoublesalary;publicStringgetName(){returnname;}publicvoidsetName(Stringname){if(name.length()>=2&&name.length()<=6){this.name=name;}else{System.out.println("输入的名称长度有误");this.name="NoOne";}}publicintgetAge(){returnage;}publicvoidsetAge(intage){if(age>=0&&age<=120){this.age=age;}else{System.out.println("输入的年龄范围不合法");this.age=-1;}}publicdoublegetSalary(){returnsalary;}publicvoidsetSalary(doublesalary){//在这可以加一些权限验证之类的this.salary=salary;}}5、快速设置set、get方法 6、封装与构造器 继承可以解决代码复用,让我们的编程更加靠近人类思维 packagecom.inherit;publicclassA{Stringname;intage;doublesalary;publicvoidinfo(){System.out.println(name+""+age+""+salary);}publicvoidcash(){System.out.println(name+"涨工资了");}}packagecom.inherit;publicclassBextendsA{publicvoidtest_b(){System.out.println("小学生"+name+"正在考试");}}packagecom.inherit;publicclassCextendsA{publicvoidtest_c(){System.out.println("大学生"+name+"正在考试");}}packagecom.inherit;publicclasstemp{publicstaticvoidmain(String[]args){Bb=newB();b.name="银角大王";//A类的共有属性nameb.age=20;//A类的共有属性ageb.salary=5000;//A类的共有属性salaryb.info();//A类的共有方法infob.test_b();//B类的特有方法test_bb.cash();//A类的共有方法cashCc=newC();c.name="金角大王";//A类的共有属性namec.age=30;//A类的共有属性agec.salary=8000;//A类的共有属性salaryc.info();//A类的共有方法infoc.test_c();//C类的特有方法test_cc.cash();//A类的共有方法cash}}1、继承细节问题 1>子类继承了父类所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过父类提供的公共方法去访问 packagecom.details;publicclassfather{publicStringname;protectedintage;doubleheight;privatedoubleweight;publicvoidf1(){System.out.println("publicf1()方法被调用");}protectedvoidf2(){System.out.println("protectedf2()方法被调用");}voidf3(){System.out.println("f3()方法被调用");}privatevoidf4(){System.out.println("privatef4()方法被调用");}//定义访问privatedoubleweight;的public方法publicvoidsetWeight(doubleweight){this.weight=weight;}publicdoublegetWeight(){returnweight;}//定义调用privatevoidf4()的public方法publicvoiduseF4(){f4();}}packagecom.details;publicclassson{publicstaticvoidmain(String[]args){fatherfather=newfather();father.name="King";father.age=20;father.height=182.5;//father.weight;这样是访问不了的father.setWeight(65.5);System.out.println(father.getWeight());//这样可以访问father.f1();father.f2();father.f3();//father.f4();这样是访问不了的father.useF4();//这样可以访问}}2>子类必须调用父类的构造器,完成父类的初始化 packagecom.details;publicclassfather{father(){System.out.println("father()构造器被调用");}}packagecom.details;publicclasssonextendsfather{son(){//这里存在super();System.out.println("son()构造器被调用");}}packagecom.details;publicclasstest{publicstaticvoidmain(String[]args){sonson=newson();//运行结果://father()构造器被调用//son()构造器被调用}}3>当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器 如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过 packagecom.details;publicclassfather{//没有指定无参构造器,如果定义了构造器,那么原来的默认无参构造器就会失效,除非显式的定义一下father(Stringname,intage){System.out.println("father(Stringname,intage)构造器被调用");}}packagecom.details;publicclasssonextendsfather{son(Stringname,intage){super("tom",20);//在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作System.out.println("son(Stringname,intage)构造器被调用");}}packagecom.details;publicclasstest{publicstaticvoidmain(String[]args){sonson=newson("name",20);//运行结果://father(Stringname,intage)构造器被调用//son(Stringname,intage)构造器被调用}}4>如果希望指定去调用父类的某个构造器,则显式的调用一下:super(参数列表) packagecom.details;publicclassfather{//在父类中定义了三个构造器father(Stringname,intage){System.out.println("father(Stringname,intage)构造器被调用");}father(){System.out.println("father()构造器被调用");}father(Stringname){System.out.println("father(Stringname)构造器被调用");}}packagecom.details;publicclasssonextendsfather{//在子类中定义三个构造器,每个构造器都可以用super去指定不同父类的构造器son(Stringname,intage){super("tom",20);System.out.println("son(Stringname,intage)构造器被调用");}son(Stringname){super("tom");System.out.println("son(Stringname)构造器被调用");}son(){super();System.out.println("son()构造器被调用");}}packagecom.details;publicclasstest{publicstaticvoidmain(String[]args){sonson=newson("name",20);//运行结果://father(Stringname,intage)构造器被调用//son(Stringname,intage)构造器被调用}}5>super在使用时,必须放在构造器第一行(super只能在构造器中使用,不能再成员方法中使用) 6>super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器 7>java所有类都是Object类的子类,Object是所有类的父类 8>父类构造器的调用不限于直接父类!将一直往上追溯直到object类(顶级父类) 9>子类最多只能继承一个父类(指直接继承),即java中是单继承机制 思考:如何让A类继承B类和C类 【A继承B,B继承C】 10>不能滥用继承,子类和父类之间必须满足is-a的逻辑关系 2、继承原理的本质分析 查找时要按照查找关系来返回信息 1>首先看子类是否有该属性,如果子类有这个属性,并且可以访问,则返回信息 2>如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息) 3>如果父类没有就按照(2)的规则,继续找上级父类,直到Object 3、继承课堂练习 编写Computer类,包含CPU、内存、硬盘等属性,getDetails方法用于返回Computer的详细信息 编写PC子类,继承Computer类,添加特有属性【品牌brand】 编写exercise类,在main方法中创建PC对象,分别给对象中特有的属性赋值,以及从Computer类继承的属性赋值,并使用方法并打印输出信息 super代表父类的引用,用于访问父类的属性、方法、构造器 1>访问父类的属性,但不能访问父类的private属性 2>访问父类的方法,不能访问父类的private方法 3>访问父类的构造器,只能放在构造器里,且为第一句,只能出现一句! packagecom.super_;publicclassfather{publicintage=10;protectedintheight=175;intsalary=8000;privateintweight=65;father(){System.out.println("father()构造器被调用");}father(intage){System.out.println("father(intage)构造器被调用");}publicvoidf1(){System.out.println("publicvoidf1()方法被调用");}privatevoidf2(){System.out.println("privatevoidf2()方法被调用");}}packagecom.super_;publicclasssonextendsfather{son(){//访问父类构造器的语法:super(参数列表);super(20);//只能放在构造器里,且为第一句,只能出现一句!System.out.println("son()构造器被调用");}publicvoids1(){intage=super.age;//访问属性的语法:super.属性名;intheight=super.height;intsalary=super.salary;//super.weight是私有属性,所以访问不了System.out.println(age+""+height+""+salary);}publicvoids2(){super.f1();//访问方法的语法:super.方法名(参数列表);//super.f2()是私有方法,所以访问不了}}packagecom.super_;publicclassrun{publicstaticvoidmain(String[]args){sonson=newson();son.s1();son.s2();}}1、super细节 1>当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super;如果没有重名,使用super、this、直接访问是一样的效果 2>super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员; 二十四、方法重写/覆盖override 方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、形参列表一样,那么就说子类的这个方法覆盖了父类的方法 packagecom.super_;publicclassfather{publicvoidm1(){//方法名称、返回类型、型参列表都一样System.out.println("father类的publicvoidm1()被调用");}}packagecom.super_;publicclasssonextendsfather{publicvoidm1(){//方法名称、返回类型、型参列表都一样System.out.println("son类的publicvoidm1()被调用");}}1、方法重写的细节 方法重写也叫方法覆盖,需要满足下面的条件 1>子类的方法的形参列表、方法名称,要和父类方法的形参列表方法名称完全一样 2>子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类(比如父类返回类型是Object,子类方法返向类型是String,String是Object的子类) packagecom.super_;publicclassfather{publicAAAm1(){returnnull;}}classAAA{//定义AAA类}classBBBextendsAAA{//BBB是AAA的子类}packagecom.super_;publicclasssonextendsfather{publicBBBm1(){//方法名称、返回类型BBB是AAA的子类、型参列表都一样returnnull;}}3>子类方法不能缩小父类方法的访问权限public>protected>默认>private 2、方法的重载和重写比较 二十五、多态 方法或对象具有多种形态,是面向对象的第三大特征,多态是建立在封装和继承基础之上的 1、多态详解 方法的多态:方法的重写和重载就体现多态 对象的多态 1>一个对象的编译类型和运行类型可以不一致 2>编译类型在定义对象时,就确定了,不能改变 3>运行类型是可以变化的 4>编译类型看定义时=号的左边,运行类型看=号的右边 5>多态的前提是两个对象(类)存在继承关系 2、向上转型 1>本质:父类的引用指向了子类的对象 2>语法:父类类型引用名=new子类类型(); 3>特点:编译类型看左边,运行类型看右边 可以调用父类中的所有成员(需遵守访问权限)、不能调用子类中特有成员、最终运行效果看子类的查找顺序 packagecom.up;publicclassfather{publicvoideat(){System.out.println("father的eat方法");}publicvoidrun(){System.out.println("father的run方法");}privatevoidcry(){System.out.println("father的cry方法");}}packagecom.up;publicclasssonextendsfather{publicvoideat(){//重写了father的eat方法System.out.println("son的eat方法");}publicvoiddrink(){//son的特有方法System.out.println("son的drink方法");}}packagecom.up;publicclassrun{publicstaticvoidmain(String[]args){fathertemp=newson();//父类的引用指向了子类的对象,叫向上转型temp.eat();//输出结果:son的eat方法temp.run();//输出结果:father的run方法//temp.drink();//这样是会报错的//temp.cry();//这样是会报错的}}向上转型细节 1>temp这个变量引用可以调用father类的所有属性和方法,但是要遵守权限,father类的private的方法就不能调用 3>temp调用运行方法时最终的运行效果要看son类(运行类型)的查找规则,由java这个程序运行,即调用方法时按照从子类向父类的顺序进行查找 总结一句话:调用方法看编译类型,执行顺序看运行类型 3、向下转型 1>语法:子类类型引用名=(子类类型)父类引用; 2>只能强转父类的引用,不能强转父类的对象 3>要求父类的引用必须指向的是当前目标类型的对象 publicclassrun{publicstaticvoidmain(String[]args){Animaltemp=cat();Dogdog=(Dog)temp;//会报错,因为原来的temp是一只羊,你不能把temp强转成一只狗}}4>当向下转型后,可以调用子类类型中所有的成员 经过向下转型之后的son指向的也是son()这个对象,此时son的编译类型是son,所以可以调用子类类型的所有成员,因为son类还继承了father类,所以son也可以调用father类的成员 4、多态注意事项 1>属性没有重写之说,属性的值看编译的类型 packagecom.up;publicclassrun{publicstaticvoidmain(String[]args){fathertemp=newson();System.out.println(temp.age);//输出结果:50System.out.println(((son)temp).age);//输出结果:25}}classfather{intage=50;}classsonextendsfather{intage=25;}2>instanceOf比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型 packagecom.up;publicclassrun{publicstaticvoidmain(String[]args){Stringname="King";fathertemp=newson();System.out.println(tempinstanceofson);//输出结果:trueSystem.out.println(tempinstanceoffather);//输出结果:trueSystem.out.println(nameinstanceofObject);//输出结果:true}}classfather{intage=50;}classsonextendsfather{intage=25;}3>向上转型的特殊写法 packagecom.up;publicclassrun{publicstaticvoidmain(String[]args){sons_temp=newson();fatherf_temp=s_temp;//向上转型,相当于fatherf_temp=newson();//注意:s_temp和f_temp是指向同一个对象的}}classfather{intage=50;}classsonextendsfather{intage=25;}5、练习题 packagecom.up;publicclassrun{publicstaticvoidmain(String[]args){Subs=newSub();System.out.println(s.count);//20属性的值看编译的类型s.display();//20Baseb=s;System.out.println(b==s);//两个对象比较的是地址trueSystem.out.println(b.count);//10属性的值看编译的类型b.display();//20向上转型调用运行方法时最终的运行效果要看运行类型的查找规则,由java这个程序运行,即调用方法时按照从子类向父类的顺序进行查找}}classBase{intcount=10;publicvoiddisplay(){System.out.println(this.count);}}classSubextendsBase{intcount=20;publicvoiddisplay(){System.out.println(this.count);}}6、动态绑定机制 1>当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定 二十六、多态数组 数组的定义类型为父类类型,里面保存的实际元素类型为子类类型 packagecom.ployarr;publicclassrun{publicstaticvoidmain(String[]args){Object[]array={"King",20,52.10,'A'};for(inti=0;i 现有一个继承结构如下: 要求创建1个Person对象、2个Student对象、2个Teacher对象,统一放在数组中,并调用每个对象的say方法,并且想办法调用Student对象和Teacher对象的私有方法 方法定义的形参类型为父类类型,实参类型允许为子类类型,应用实例:前面的主人喂动物 应用实例: 定义员工类Employee,包含姓名和月工资[private],以及计算年工资getAnnual的方法 普通员工和经理继承了员工,经理类多了奖金bonus属性和管理manage方法,普通员工类多了work方法,普通员工和经理类要求分别重写getAnnual方法 测试类中添加一个方法showEmpAnnual(Employeee),实现获取任何员工对象的年工资,并在main方法中调用该方法[e.getAnnual()] 测试类中添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用manage方法 ==是一个比较运算符 1、==既可以判断基本类型,又可以判断引用类型 2、==如果判断基本类型,判断的是值是否相等(示例:inti=10;doubled=10.0;) 3.、==如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象 packagecom.com;publicclassequals_{publicstaticvoidmain(String[]args){Integernum1=newInteger(5);Integernum2=newInteger(5);//==如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象System.out.println(num1==num2);//falseintnum3=50;doublenum4=50.0;//==如果判断基本类型,判断的是值是否相等System.out.println(num3==num4);//true}}4、equals是Object类中的方法,只能判断引用类型 5、equals默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等 //Object类的equals方法publicbooleanequals(Objectobj){return(this==obj);}//String类重写了equals方法publicbooleanequals(ObjectanObject){if(this==anObject){returntrue;}if(anObjectinstanceofString){StringaString=(String)anObject;if(coder()==aString.coder()){returnisLatin1()StringLatin1.equals(value,aString.value):StringUTF16.equals(value,aString.value);}}returnfalse;}//Integer类重写了equals方法publicbooleanequals(Objectobj){if(objinstanceofInteger){returnvalue==((Integer)obj).intValue();}returnfalse;}packagecom.com;publicclassequals_{publicstaticvoidmain(String[]args){Objecttemp=newObject();Objecttest=temp;//equals默认判断的是地址是否相等System.out.println(temp.equals(test));//trueStringstr="King";Stringstr1="King";Stringstr2="mark";//子类中往往重写该方法,用于判断内容是否相等System.out.println(str.equals(str1));//trueSystem.out.println(str.equals(str2));//false}}备注:ctrl+B可以查看当前的方法的JDK源码 应用实例:判断两个tools对象的内容是否相等,如果两个tools对象的各个属性值都一样,则返回true,反之false packagecom.equalshomework;publicclassPerson{publicstaticvoidmain(String[]args){toolsa=newtools("zrh",20,'男');toolsb=newtools("zrh",20,'男');System.out.println(a.equals(b));}}classtools{privateStringname;privateintage;privatechargender;publictools(Stringname,intage,chargender){this.name=name;this.age=age;this.gender=gender;}publicbooleanequals(Objectobj){//重写了equals方法if(this==obj){//==如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象returntrue;}elseif(objinstanceoftools){toolst=(tools)obj;//向下转型,为了可以拿到对象的属性值returnthis.name.equals(t.name)&&this.age==t.age&&this.gender==t.gender;}returnfalse;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){returnage;}publicvoidsetAge(intage){this.age=age;}publicchargetGender(){returngender;}publicvoidsetGender(chargender){this.gender=gender;}}二十九、hashCode方法 1、提高具有哈希结构的容器的效率 2、两个引用,如果指向的是同一个对象,则哈希值肯定是一样的 3、两个引用,如果指向的是不同对象,则哈希值是不一样的 4、哈希值主要根据地址号来的,不能完全将哈希值等价于地址 5、在集合中hashCode如果有需要的话,会进行重写 packagecom.hashCode;publicclasshashCode{publicstaticvoidmain(String[]args){testtest1=newtest();testtest2=newtest();testtest3=test1;System.out.println(test1.hashCode());//1239731077System.out.println(test2.hashCode());//557041912System.out.println(test3.hashCode());//1239731077}}classtest{}三十、toString方法 基本介绍 默认返回:全类名+@+哈希值的十六进制 1、子类往往重写toString方法,用于返回对象的属性信息 2、重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式. 3、当直接输出一个对象时,toString方法会被默认的调用,比如System.out.printIn(monster);就会默认调用monster.toString() //查看Object的toString方法publicStringtoString(){returngetClass().getName()+"@"+Integer.toHexString(hashCode());}packagecom.toString_;publicclasstoString_{publicstaticvoidmain(String[]args){catcat=newcat();System.out.println(cat.toString());//com.toString_.cat@49e4cb85mastermaster=newmaster();System.out.println(master.toString());//master{name='King',age=20}//当直接输出一个对象时,toString方法会被默认的调用System.out.println(cat);//等价于System.out.println(cat.toString());System.out.println(master);//等价于System.out.println(master.toString());}}classcat{}classmaster{privateStringname="King";privateintage=20;@OverridepublicStringtoString(){return"master{"+"name='"+name+'\''+",age="+age+'}';}}三十一、finalize方法 1、当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作 2、什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法 3、垃圾回收机制的调用,是由系统来决定(即有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制 我们在实际开发中,几乎不会运用finalize,所以更多就是为了应付面试 packagecom.finalize_;publicclassfinalize_{publicstaticvoidmain(String[]args){carcar=newcar("宝马");car=null;//这时car对象就是一个垃圾,垃圾回收器就会回收(销毁)对象//在销毁对象前,会调用该对象的finalize方法//程序员就可以在finalize中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件..)//如果程序员不重写finalize,那么就会调用Object类的finalize,即默认处理System.gc();System.out.println("程序执行完毕");}}classcar{Stringname;publiccar(Stringname){this.name=name;}@Overrideprotectedvoidfinalize()throwsThrowable{System.out.println("释放资源……");}}//执行结果://释放资源……//程序执行完毕三十二、断点调试 F7(跳入方法内) alt+shift+F7(强制进入) F8(逐行执行代码) shift+F8(跳出方法) F9(resume,直接执行到下一个断点) Ideadebug如何进入Jdk源码 解决方法1:使用forcestepinto:快捷键alt+shift+F7 解决方法2:配置一下就好了 点击Setting-->Build,Execution,Deployment-->Debugger-->Stepping 把Donotstepintotheclasses中的java.*,javax.*取消勾选 三十三、零钱通案例 工具集类为将事先用到的方法都先写好,在service类里直接调用即可,例如:接受用户输入+输入正确值判断等 我们在拿到需求进行分析的时候,应该从用户的角度去进行分析,在代码实现的时候应该从下往上去实现 packagetest;publicclasstest{publicstaticvoidmain(String[]args){run.A();//因为A方法为static,所以不需要创建对象就可以直接调用//运行结果:test包下的static的A方法}}packagetest;publicclassrun{publicstaticvoidA(){System.out.println("test包下的static的A方法");}}