爆肝3万5千字的Java学习笔记(超详细的java)
Java学习
java入门
java三大版本
- javaSE:标准版(桌面程序,控制台开发…)
- javaME:嵌入式开发(手机,小家电…)
- javaEE:E企业级开发(web端,服务器开发…)
Java特性和优势
- 简单性
- 面向对象
- 可移植性(各平台连通)
- 高性能
- 分布式
- 动态性(反射)
- 多线程
- 安全性
- 健壮性
java开发环境搭建
jdk下载与安装
- 百度搜索JDK8,找到下载地址
- 同意协议
- 下载电脑对应的版本
- 双击运行安装
- 记住安装路径
- 配置环境变量
- 我的电脑-》右键-》属性
- 环境变量-》JAVA_HOME
- 配置path变量
- 测试JDK是否安装成功
- 打开cmd
- 输入java-version命令
HelloWorld及简单语法规则
public class Hello{public static void main(String[] args){System.out.println("Hello World");}
}
个人建议用idea来写代码方便很多!!
- 类名和文件名保持一致
- 中文名可能会出现乱码的情况
- 符号都是英文符号
卸载jdk(不需要这个jdk时候删)
删除Java的安装目录
删除JAVA_HOME
删除path下关于Java的目录
Dos执行java-version命令(提示找不到文件即为删除完毕)
IDEA安装与优化
链接:https://pan.baidu.com/s/1AmZzq-05JlADF4IxLZBZHQ
提取码:zcgc
IDEA优化
参考文章https://blog.csdn.net/zeal9s/article/details/83544074
Java基础
注释
注释不会被执行,方便我们在复杂的项目中排查问题
分类
- 单行注释(//)
public class Main {public static void main(String[] args) {// write your code here}
}
- 多行注释(/*回车)
public class Main {public static void main(String[] args) {/*多行注释*/}
}
- 文档注释(/**回车)
public class Main {public static void main(String[] args) {/*** 文本注释*/}
}
标识符与关键字
Java所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
标识符注意点
- 所有的标识符都应该以字母(A-Z或者a-z),美元符($)、或者下划线(_)开始
- 首字符之后可以是字母(A-Z或者a-z),美元符($)、下划线(_)或者数字的任意字符组合
- 不能使用关键字作为变量名或方法名
- 标识符是大小写敏感的
数据类型
强类型语言
要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用
弱类型语言
Java数据类型分为两类
基本类型
- 数值类型
整数类型
byte占1个字节:-128-127
short占2字节:-32768-32767
int占4字节:-2147483648-2147483648
long占8字节:-9223372036854775808-9223372036854775807
浮点类型
float占4字节
double占8个字节
字符类型
char占2个字节
- Boolean类型:false&true
public class javatest {public static void main(String[] args) {//整数int num = 10;byte num1 = 10;short num2 = 10;long num3 = 30L;//Long类型要在数字后面加个L//小数float num5 = 50.1F;//float类型在数字后面加一个Fdouble num6 = 3.13176381;//字符char name='果';//布尔值:是非boolean flag=true;}
}
引用类型
类
接口
数组
字节
位(bit):计算机内部数据存储最小的单位
字节(byte):计算机中数据处理的基本单位,习惯用大写B表示
1B=8bit:1字节等于8位
字符:指计算机中使用的字母、数字、字、符号
数据类型扩展以及面试详解
public class javatest {public static void main(String[] args) {int i=10;int i2=010;//八进制"0"int i3=0x10;//十六进制"0x"//二进制"0b"//=======================================//float 有限 离散 舍入误差 大约 接近但不等于float f=0.1f;double d=1.0/10;System.out.println(f == d);//flase//f和d的输出是一样System.out.println(f);System.out.println(d);float d1=1467899234f;float d2=d1+1;System.out.println(d1==d2);//true//============================//字符拓展//=======================char c1='a';char c2='中';System.out.println((int)c1);//强制转换//所有支付本质是数字//编码 Unicaode表: 2字节char c3='\u0061';System.out.println(c3);//a//转义字符// \t 制表符// \n 换行System.out.println("hellow\nworld");//=============================String sa=new String("hello");String sb = new String("hello");System.out.println(sa==sb);//此处输出为false//原因:每一次new都是在申请一个空间,内存地址不一样String sc="hello";String sd="hello";System.out.println(sc=sd);//此处输出为true//对象 从内存分析//布尔值扩展boolean flag=true;if(flag==true){}//新手if(flag){}//老手}
}
类型转换
- 由于Java是强类型语言,所以要进行有些运算的时候,需要进行有些运算的时候的,需要用到类型转换
//低---------------------高byte,short,char->int->long->float->double
运算中,不同类型的数据先转化为同一数据再运算
强制类型转换(高-》低)
自动类型转换(低-》高)
public class javatest {public static void main(String[] args) {int i = 128;//强制转换 (类型)变量名 高-低//自动转换 低-高byte b=(byte)i;//内存溢出//double b=i; 不会报错/*注意点:1.不能对布尔值进行转换2.不能把对象类型转换为不相干的类型3.在把高容量转为低容量,强制转换4.转换的时候可能会存在溢出,或者精度问题!*/System.out.println((int)23.5);//会导致精度丢失System.out.println("============");char c='a';int d=c+1;//强转数字为dSystem.out.println(d);//输出98System.out.println((char)d);//强转回b}
}
数据越界问题简单解析
public class javatest { public static void main(String[] args) { //操作比较大的数的时候,注意溢出问题 //JDK7新特性,数字之间可以用下划线分割(注意jdk版本) int money=10_0000_0000; int years=20; int total1=money*years;//-1474836480,计算时候溢出 long total2=money*years;//默认是int,转换之前可能就出来问题 long total3=money*((long)years);//先把一个数转换为long,则不会越界 System.out.println(total1); System.out.println(total2); System.out.println(total3); }}
变量、常量、作用域
变量
变量是什么?
就是一个可变的量
Java是一种强类型语言,每个变量都必须声明其类型
Java变量是程序中最基础的单元,其元素包括变量名,变量类型和作用域
type varName [=value][{,varName[=value]}];
//数据类型 变量名=值;
//可以使用逗号分开来声明多个同类型变量
注意事项:
每个变量都有类型,类型可以是基本类型,也可以是引用类型
变量名必须是合法的标识符
变量声明是一条完整的语句,因此每一个声明都必须以分号结束
public class javatest {//类变量 staticstatic double salary=2500//属性变量//实例变量:从属于对象;如果不自行初始化,这个类型的默认值 0 0.0//布尔值:默认是flase//除了基本类型,其余的默认值都是null;String name;int age;public static void main(String[] args) {//局部变量:必须声明和初始化值int i=10;System.out.println(i);//变量类型 变量名字(随便自己定)=new javatest s=new javatest();//类变量 staticSystem.out.plintln(salary);}//其他方法public void add(){}
}
常量
.初始化后不能再改变的值,不可变动的值
所谓常量可以理解为一种特殊的变量,它的值设定之后,在程序运行过程中不允许被改变
final 常量名=值;final double PI=3.14;
常量名一般使用大写字符
变量命名规范
- 所有变量、方法、类名:见名知意
- 类成员变量:首字母小写和驼峰原则:mouthSalary 除了第一个单词以外,后面的单词首字母大写 lastName
- 局部变量:首字母小写和驼峰原则
- 常量:大写字母和下划线 MAX_VALUE
- 类名:首字母大写和驼峰原则:Man,GoodMan
- 方法名:首字母小写和驼峰原则 run().runRun()
运算符
Java支持的运算符:
- 算术运算符:+,-,*,/,%,++,–
- 赋值运算符:=
- 关系运算符:> ,<, >= ,<= ,== ,!=
- 逻辑运算符:&&,||,!
- 位运算符:&,|,^, ~, >>,<<,>>>(了解)
- 条件运算符:?:
- 扩展赋值运算符:+=,-=,*=,/=
基本运算符
基础运算
public class javatest {public static void main(String[] args) {int a=10;int b=20;System.out.println(a+b);System.out.println(a-b);System.out.println(a*b);System.out.println(a/b);//算出来为0,默认的是int类型System.out.println(a/(double)b);//输出结果为0.5}
}
类型转换实例
public class javatest {public static void main(String[] args) {long a=1242545362L;int b=10;short c=10;byte d=8;System.out.println(a+b+c+d);//long类型存在的时候结果为longSystem.out.println(b+c+d);//没有long类型默认int;System.out.println(c+d);}
}
关系运算符
public class javatest {public static void main(String[] args) {//关系运算符运行的结果为 true或者flase 布尔值int a=10;int b=20;int c=3;System.out.println(a>b);//long类型存在的时候结果为longSystem.out.println(a<b);//没有long类型默认int;System.out.println(a=b);System.out.println(a%c);//模运算,也就是取余数}
}
自增自减运算符即Math工具类方法
public class javatest { public static void main(String[] args) { //++ -- 自增自减 一元运算符 int a=3; //执行代码后,先给b赋值,再自增 int b=a++; //执行完代码后,先自增,再给c赋值 int c=++a; System.out.println(a); System.out.println(b); System.out.println(c); //幂运算 2^3 很多运算需要用到工具类来操作 Math.pow(2,3); }}
逻辑运算符,位运算符
逻辑运算
public class javatest { public static void main(String[] args) { //与 或 非 boolean a=true; boolean b=false; //逻辑与运算:两个数都为真,结果才为真 System.out.println("a&&b:" + (a && b)); //逻辑或运算,两个数有一个为真就为真 System.out.println("a||b:" + (a || b)); //如果为真,则为假 System.out.println("!(a&&b:)"+!(a&&b)); //短路运算 int c=5; boolean d=(c<4)&&(c>3); System.out.println(d); }}
位运算
public class javatest { public static void main(String[] args) { /* a=0011 1100 b=0000 1101 --------------- a&b=0000 1100 a|b=0011 1101 a^b=0011 0001 ~b=1111 0010 << :左移 本质是*2 >> :右移 本质是/2 */ System.out.println(2<<3);//结果为16 }}
三元运算符
public class javatest { public static void main(String[] args) { int a=10; int b=20; a+=b;//a=a+b; a-=b;//a=a-b; //字符串连接符+ System.out.println(""+a+b);//双引号在前面是字符串拼接 System.out.println(a+b+"");//双引号在后面会将前面的运算 }}
public class javatest { public static void main(String[] args) { //x?y:z //如果x==true,则结果y,否则为结果z int score =50; String type=score<60 ?"不及格":"及格"; //if System.out.println(type); }}
运算符优先级
java 语言中运算符的优先级共分为 14 级,其中 1 级最高,14 级最低
优先级 | 运算符 | 结合性 |
---|---|---|
1 | ()、[]、{} | 从左到右 |
2 | !、+、-、~、++、– | 从左到右 |
3 | *、/、% | 从左到右 |
4 | +、- | 从左到右 |
5 | «、»、>>> | 从左到右 |
6 | <、<=、>、>=、instanceof | 从左到右 |
7 | ==、!= | 从左到右 |
8 | & | 从左到右 |
9 | ^ | 从左到右 |
10 | | | 从左到右 |
11 | && | 从左到右 |
12 | || | 从左到右 |
13 | ?: | 从左到右 |
14 | =、+=、-=、*=、/=、&=、|=、^=、~=、«=、»=、>>>= | 从左到右 |
包机制
为了更好地组织类,java提供了包机制,用于区别类名的命名空间
包语句的语法结构为:
package pk1[.pk2[.pk3..]];
一般来说利用公司域名倒置作为包名
如:www.baidu.com;建包的时候就是com.baidu.www
为了能够使用某一个包的成员,我们需要在java程序中明确导入包,使用import语句可以完成
import package1[.package2[.package3]].(classname|*);
JavaDoc
- 用来生成自己的API文档
- 参数信息
- @author作者名
- @version版本号
- @since指明需要最早使用的jdk版本
- @param参数名
- @return返回值情况
- @throws异常抛出情况
public class javatest { String name; /** * * @param name * @return * @throws Exception */ public String test(String name) throws Exception{ return name; } //学会查找使用idea生产javaDoc文档! //基础部分的一切知识,后面每天都会用到}
找到创建的class类的目录,在此目录下打开cmd运行命令 Javados 参数 xxx.java
会在当前目录下生成一个index.html文件也就是首页,打开就会发现一些简单的东西
Java流程控制
用户交互Scanner
Scanner对象
我们首先知道以前的基本语法没有实现程序和人的交互,但是Java.util.Scanner是Java5新特性,我们可以通过Scanner类来获取用户的输入
Scanner s=new Scanner(System.in)
通过Scanner类的next()与nextLine()方法获取输入的字符串,在读取前一般需要使用hasNext()与hasNextLine()判断是否还有输入的数据
import java.util.Scanner;public class javatest { public static void main(String[] args) { //创建一个扫描器对象,用于接收键盘数据 Scanner scanner = new Scanner(System.in); System.out.println("使用next方式接收"); //判断用户有没有输入字符串 if (scanner.hasNext()) { //使用next方式接收 String str = scanner.next(); System.out.println("输出内容为:" + str); } //凡是属于IO流的类如果不关闭会一直占用资源,要养成良好习惯用完关掉 scanner.close(); }}
next():
- 一定要读取有效字符后才可以结束输入
- 对输入有效字符之前遇到的空白,next()方法会自动将其去掉
- 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符
- next()不能得到带有空格的字符串
package com.company;import java.util.Scanner;public class Main { public static void main(String[] args) { //创建一个扫描器对象,用于接收键盘数据 Scanner scanner = new Scanner(System.in); System.out.println("使用nextLine方式接收"); //判断用户有没有输入字符串 if (scanner.hasNextLine()) { //使用next方式接收 String str = scanner.nextLine(); System.out.println("输出内容为:" + str); } scanner.close(); }}
nextLine():
- 以Enter为结束符,也就是说nextLint()方法返回的是输入回车之前的所有字符
- 可以获得空白
Scanner进阶使用
package com.company;import java.util.Scanner;public class Main { public static void main(String[] args) { Scanner scanner=new Scanner(System.in); int i; float f; System.out.println("请输入整数:"); if(scanner.hasNextInt()){ i=scanner.nextInt(); System.out.println("输出整数为:"+i); }else { System.out.println("输出不为整数!"); } System.out.println("请输入小数:"); if(scanner.hasNextFloat()){ f=scanner.nextFloat(); System.out.println("输出小数为:"+f); }else { System.out.println("输出不为小数!"); } scanner.close(); }}
举一个例子
package com.company;import java.util.Scanner;public class Main { public static void main(String[] args) { //我们可以输入多个数字,并求其总和与平均值,每输入一个数字用回车确认,通过输入非数字来结束输入并输出执行结果; Scanner scanner=new Scanner(System.in); double sum=0; int m=0; //输入除了double类型,直接退出,否则一直执行 while(scanner.hasNextDouble()){ double x=scanner.nextDouble(); m++; sum=x+sum; System.out.println(m+"m个数字:"+"所求得的和为sum"+sum); } scanner.close(); }}
顺序结构
- JAVA的基础结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行
- 顺序结构是最简单的算法结构
- 语句与语句之间,框与框之间是按从上到下的顺序进行的,它是由若干个依次执行的处理步骤组成的,它是任何一个算法都离不开的一种基本算法结构
package com.company;import java.util.Scanner;public class Main { public static void main(String[] args) { System.out.println("1"); System.out.println("2"); System.out.println("3"); }}
选择结构
if单选择结构
package com.company;import java.util.Scanner;public class Main { public static void main(String[] args) { Scanner scanner=new Scanner(System.in); System.out.println("请输入字符串:"); String s = scanner.nextLine(); //equals判断是否相等 if(s.equals("hello")){ System.out.println(s); } System.out.println("end"); scanner.close(); }}
- 语法
if(布尔表达式){ //如果布尔表达式为true}
if双选择结构
package com.company;import java.util.Scanner;public class Main { public static void main(String[] args) { Scanner scanner=new Scanner(System.in); System.out.println("请输入数字:"); int s = scanner.nextInt(); if(s>60){ System.out.println("及格"); }else { System.out.println("不及格"); } scanner.close(); }}
- 语法
if(布尔表达式){ //如果布尔表达式为true}else{ //如果布尔表达式为false}
if多选择结果
package com.company;import java.util.Scanner;public class Main { public static void main(String[] args) { Scanner scanner=new Scanner(System.in); System.out.println("请输入数字:"); int s = scanner.nextInt(); if(s>60&s<=70){ System.out.println("良"); }else if(s>70&s<90){ System.out.println("优"); }else if(s>=90){ System.out.println("强!"); }else{ System.out.println("不及格"); } scanner.close(); }}
- 语法
if(布尔表达式1){ //如果布尔表达式1的值为true执行代码}else if(布尔表达式2){ //如果布尔表达式2的值为true执行代码}else if(布尔表达式3){ //如果布尔表达式3的值为true执行代码}else{ //如果以上布尔表达式都不为true执行代码}
嵌套的if结构
package com.company;import java.util.Scanner;public class Main { public static void main(String[] args) { Scanner scanner=new Scanner(System.in); System.out.println("请输入数字:"); int s = scanner.nextInt(); if(s>50){ System.out.println(s); if(s>90){ System.out.println(s); } } scanner.close(); }}
- 语法
if(布尔表达式1){ //如果布尔表达式1的值为true执行代码 if(布尔表达式2){ //如果布尔表达式2的值为true执行代码 }}
switch多选择结构
- switch case 语句判断一个变量与一系列值中某个值是否相等,每个值成为一个分支
- switch语句中的类型变量可以是
- byte、short、int、char
- 从JavaSE7开始
- switch支持字符串类型
- 同时case标签必须为字符串常量或字面量
package com.company;public class Main { public static void main(String[] args) { String name="kongkong"; switch(name){ case "kongkong": System.out.println("你好"); case "xiangxiang": System.out.println("我好"); default: System.out.println("大家好"); } }}
输出的结果是”你好我好大家好“,这是因为没有加break语句跳出执行的结果,下面加上可见
public static void main(String[] args) { String name="kongkong"; switch(name){ case "kongkong": System.out.println("你好"); break; case "xiangxiang": System.out.println("我好"); break; default: System.out.println("大家好"); break; }
- 语法
switc(expression){ case value: //语句 break;//可选 case value: break; //你可以有任意的case语句 default:}
我们去它的当地目录下查看可以看到反编译文件.class
循环结构
while循环
- 结构
while(布尔表达式){ //循环内容}
- 只要布尔表达式为true,就能一直执行下去
- 大多数情况是会让循环停下来,我们需要一个让表达式失效的方式结束循环
- 小部分情况需要一直执行,比如服务器的请求响应监听等
- 循环一直为true会造成无限循环【死循环】,我们需要避免死循环,会影响程序性能或造成程序卡死奔溃
- 思考1+2+3+4+5+…+100
package com.company;public class Main { public static void main(String[] args) { int m=1; double sum=0; while(m<=100){ sum+=m; m++; } System.out.println(sum); }}
do…while循环
- 对于while而言,如果不满足条件,则不会进入循环。但有的时候我们需要即使不满足条件,也至少执行一次。
- do…while循环和while循环相似,不同的是,do…while至少会执行一次。
- 语法
do{ //循环语句}while(布尔表达式);
package com.company;public class Main { public static void main(String[] args) { int m=1; double sum=0; do{ sum+=m; m++; }while (m<=100); System.out.println(sum); }}
while和do…while区别
- while先判断后执行,do…while先执行后判断
- do…while总是保证循环体会至少被执行一次,这是他们的主要区别
package com.company;public class Main { public static void main(String[] args) { int i=0; while(i<0){ System.out.println(i);//判断失败,退出执行 i++; } System.out.println("=========="); do{ System.out.println(i);//先执行再判断,发现失败但已执行 }while(i<0); }}
for循环
for循环语句是支持迭代的一种通用结构,是最有效,最灵活的循环结构
for循环执行的次数是在执行前就确定的,语法格式如下
for(初始化,布尔表达式,更新){//循环语句}
package com.company;public class Main { public static void main(String[] args) { int i=0;//初始值 while(i<=100){//条件语句 System.out.println(i);//循环体 i+=2;//迭代 } //初始值//条件判断//迭代 for (int i1 = 0; i1 < 100; i1++) { System.out.println(i1); } //死循环 for(; ; ){ } }}
思考
- 计算0-100之间奇数和偶数的和
方法一
package com.company;public class Main { public static void main(String[] args) { int sum1=0,sum2=0; //偶数的相加 for (int i = 0; i <= 100; i=i+2) { sum1+=i; } //奇数的相加 for (int i = 1; i <= 100; i+=2) { sum2+=i; } System.out.println(sum1); System.out.println(sum2); }}
方法二
package com.company;public class Main { public static void main(String[] args) { int sum1=0,sum2=0;//通过if-else的判断,在循环的时候就把奇数偶数分离开来 for (int i = 0; i <= 100; i++) { if(i%2==0){ sum2+=i;//偶数 sum2=sum2+i }else{ sum1+=i;//奇数 } } System.out.println(sum1); System.out.println(sum2); }}
用while或for循环输出1-1000之间能被5 整除的数,并且每行输出3个
package com.company;public class Main { public static void main(String[] args) { int count=0; for (int i = 1; i <= 1000; i++) { if(i%5==0){ System.out.print(i+" "); count++; } if(count%3==0){ System.out.println(); } } }}
打印九九乘法表
方法一
package com.company;public class Main { public static void main(String[] args) { int count=0; for (int i = 1; i <= 9; i++) {//for循环i表示行循环 for (int j = 1; j <=9; j++) {//for循环j表示列循环 if(i>=j)//去重操作 System.out.print(j+"*"+i+"="+i*j+" "); count++;//加一个计数值便于换行 } if(count%i==0){ System.out.println(); } } }}
方法二
package com.company;public class Main { public static void main(String[] args) { /* 1.我们先打印第一列 2、我们把固定的1再用循环抱起来 3、去掉重复项,i<=j 4、调整样式 */ for (int i = 1; i <= 9; i++) { for (int j = 1; j<=i; j++) { System.out.print(j+"*"+i+"="+i*j+"\t"); } System.out.println(); } } }
增强for循环
- 语法
for(声明语句:表达式){ //代码句子}
- 声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配,其作用域限定在循环语句块,其值与此时数组元素的值相等
- 表达式:表达式是要访问的数组名,或者是返回值为数组的方法
package com.company;public class Main { public static void main(String[] args) { int[] number={12,123,13,12,42}; for (int i = 0; i < 5; i++) { System.out.println(number[i]); } System.out.println("============"); for(int x :number){ System.out.println(x); } } }
break&continue
- break在任何循环语句的主体部分中,均可用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句(break也能在switch中使用)
package com.company;public class Main { public static void main(String[] args) { for (int i = 0; i < 100; i++) { System.out.println(i); if(i==30){ break;//执行到30即刻跳出循环 } } } }
- continue语句用在循环语句中,用于终止某次循环过程,即跳过循环体中,尚未执行的语句,接着进行下一次是否执行循环的判定
package com.company;public class Main {public static void main(String[] args) {for (int i = 0; i < 100; i++) {if(i%10==0){continue;//i=10的倍数的时候在这里跳回循环,没有往下执行}System.out.println(i);}}}
- goto关键字(了解,不建议使用)
package com.company;public class Main {public static void main(String[] args) {//打印101-150之间的质数int count=0;outer:for (int i = 101; i <150 ; i++) {for (int j = 2; j <i/2 ; j++) {if(i%j==0){continue outer;}}System.out.println(i+" ");}}}
打印三角形
package com.company;public class Main { public static void main(String[] args) { //三角形 for (int i = 1; i <= 5; i++) { for (int j = 5; j >=i; j--) { System.out.print(" "); } for (int j = 1; j <=i; j++) { System.out.print("*"); } for(int j=1;j<i;j++){ System.out.print("*"); } System.out.println(); } }}
java方法
什么是方法
System.out.println();//类.对象.方法
- 方法是语句的集合,它们在一起执行一个功能
- 方法是解决一类问题的步骤的有序组合
- 方法包含于类或对象中
- 方法在程序中被创建,在其他地方被引用
- 设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成一个功能,这样有利于我们后期的扩展
package com.company;public class Main {//main方法 public static void main(String[] args) { int sum=add(1,3);//调用add方法 System.out.println(sum); } //add方法 public static int add(int a,int b){ return a+b; }}
定义
java的方法类似于其他语言的函数,是一段用来完成特殊功能的代码片段,一般情况下,定义一个方法包含以下语法
方法包含一个方法头和一个方法体,下面是方法的所有部分:
- 修饰符:告诉编译器如何调用该方法,定义了该方法的访问类型
- 返回值类型:方法可能会返回值。returnVlaueType是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnVlaueType是关键词void
- 方法名:是方法的实际名称。方法名和参数表共同构成方法签名
- 参数类型:参数像一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型,顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
- 形式参数:在方法被调用时用于接收外界的数据
- 实参:调用方法时实际传给方法的数据
- 方法体:方法体包含具体的语句,定义该方法的功能。
修饰符 返回值类型 方法名(参数类型 参数名){ 。。。 方法体 。。。 return 返回值;}
package com.company;public class Main { public static void main(String[] args) { int min = min(21, 124); System.out.println(min); } public static int min(int a,int b){ if (a==b){ System.out.println("两个数相等"); return 0; } if(a>b){ return b; }else { return a; } }}
方法调用
调用方法:对象名.方法名(实参列表)
Java支持两种调用方法的方式,根据方法是否返回值来选择
当方法返回一个值的时候,方法调用通常被当作一个值。如
int m=max(30,28);
如果方法返回值为void,方法调用一定是一条语句
System.out.println("kongkong");
值传递(java)和引用传递
值传递
- 形式参数类型是基本数据类型
- 方法调用时,实际参数把它的值传递给对应的形式参数
- 形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元
- 方法执行中形式参数值的改变不影响实际参数的值
引用传递
- 形式参数类型是引用数据类型参数,也称为传地址。
- 方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址
- 在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来
- 方法执行中形式参数的改变将会影响实际参数。
进一步理解
Java的方法参数传递只有一种,就是值传递
如果是基本类型,就是将原有的数据拷贝一份,方法内的操作对原有的数据不会有影响。
如果是对象类型,这里是容易误解的地方,因为正好规定对象的地址也叫做"reference", 我们将对象作为参数传递的时候实际上是将对象的地址传递进去。
即使传递的对象,也是传递对象的地址(英文就叫reference了)的值!(值传递!!)
方法的重载
- 重载就是在一个类中,有相同的函数名称,但形参不同的参数
- 方法的重载规则
- 方法名必须相同
- 参数列表必须不同(个数不同,类型不同,参数排序顺序不同)
- 方法的返回值类型可以相同,可以不同
- 仅仅返回类型不同不足以成为方法的重载
- 实现理论:
- 方法名称相同的时候,编译器会根据调用方法的参数个数,参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错
package com.company;public class Main { public static void main(String[] args) { //int min = min(21, 21); double min=min(21,421); System.out.println(min); } //double min(double a,double b) public static double min(double a,double b){ if (a==b){ System.out.println("两个数相等"); return 0; } if(a>b){ return b; }else { return a; } } //int min(int a,int b) public static int min(int a,int b){ if (a==b){ System.out.println("两个数相等"); return 0; } if(a>b){ return b; }else { return a; } }}
命令行传参
- 有时候希望你运行一个程序时候再给它传递消息。重要靠传递命令行参数给main()函数实现
- 编译包的时候:找到目录输入javac xxxx.java
- 运行包时:回退到src目录下面 输入Java 包路径名 参数
可变参数
- jdk1.5开始,java支持同类型的可变参数给一个方法
- 在方法声明中,在指定参数类型后加一个省略号(…)
- 一个方法只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数都必须在它之前声明
package com.company;public class Main { public static void main(String[] args) { printMax(12,41,41,24,52,63); } //...自由定义多个变量值 public static void printMax(double... numbers){ if(numbers.length==0){ System.out.println("please put passed"); return; } double result=numbers[0]; for (int i = 0; i < numbers.length; i++) { if(numbers[i]>result){ result=numbers[i]; } } System.out.println("the max is "+result); }}
递归
package com.company;public class Main { public static void main(String[] args) { System.out.println(f(4)); } public static int f(int n){ if(n==1){ return 1; }else{ return n*f(n-1); } }}
- 能不用递归就不用递归
- 递归通过栈,调用次数太多,容易导致电脑卡崩
数组
什么是数组
定义
- 数组是相同类型数据的集合
- 数组描述的是相同类型的若干个数据,按照一定的先后顺序排序组合而成
- 其中,每一个数据称作一个数组元素,每个元素可以通过一个下标来访问他们
四个基本特点
长度是确定的。一旦被创建,大小就是不可改变的
元素必须是相同的,不允许是混合类型
元素可以是任何类型,包括基本类型和引用类型
变量属于引用类型,数组也可以看成是对象,每个元素相当于该对象的成员变量
数组本身就是对象,Java中对象是在堆中的,因此无论保存原始类型还是其他类型,本身是在堆中的
数组声明和创建
首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法
dataType[] arrary;//首选的方法dataType arrary[];//效果相同,不建议使用
java语言使用new操作来创建数组,语法
dataType arrary=new dataType[arrarySize];
数组的元素是通过索引访问的,数组索引从0开始。
获取数组长度:arrary.length
数组默认创建值为0
package com.company;public class Main { public static void main(String[] args) { int[] sum;//声明一个数组 sum=new int[10];//创建一个数组 //给数组元素中赋值 sum[0]=1; sum[1]=2; sum[2]=3; sum[3]=4; sum[4]=5; sum[5]=6; sum[6]=7; sum[7]=8; sum[8]=9; sum[9]=10; int result=0; //获取数组长度:sum.length for (int i = 0; i <sum.length; i++) { result =sum[i]+result; } System.out.println(result); }}
内存分析
java内存
- 堆
- 存放new的对象和数组
- 可以被所有的线程分享,不会存放别的对象引用
- 栈
- 存放基本变量类型(会包含这个基本类型的具体数值)
- 引用对象的变量(会存放这个引用在堆里面的具体地址)
- 方法区
- 可以被所有的线程共享
- 包含所有的class和static变量
数组的三种初始化
- 静态初始化
int[] a={1,2,3}Man[] mans = {new Man(1,1),new Man(2,2)};
- 动态初始化(手动赋值)
int[] a = new int[2];a[0]=1;a[1]=2;
- 数组的默认初始化
- 数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,元素也会被按照实例变量同样方式被隐式初始化
package com.company;public class Main { public static void main(String[] args) { //静态初始化:创建+赋值 int[] a={1,2,3,4,5,6,7,8,9}; System.out.println(a[0]); //动态初始化:包含默认初始化 int[] b=new int[2]; b[1]=2; System.out.println(b[1]); System.out.println(b[0]);//没有给b[0]赋值,默认输出值为0 }}
数组边界
下标的合法区间:[0,length-1],如果越界就会报错:
public static void main(String[] args){ int[] a=new int[2]; System.out.println(a[2]);}
ArrayIndexOutOfBoundsException:数组下标越界异常!
小结
- 数组是相同数据类型(数据类型可以为任意类型)的有序集合
- 数组也是对象。数组元素相当于对象的成员变量
- 数组长度的确定的,不可变的。如果越界,就会报错
数组使用
首先我们先看传统的数组使用,如下(普通的for循环)
package com.company;public class Main { public static void main(String[] args) { int[] a={1,2,3,4,5,6,7,8}; //遍历输出每一个数组元素 for (int i = 0; i <a.length ; i++) { System.out.println(a[i]); } System.out.println("==============="); int sum=0; //求每一个数组相加和 for (int i = 0; i <a.length ; i++) { sum+=a[i]; } System.out.println(sum); //求最大值 int max=a[0]; for (int i = 0; i <a.length ; i++) { if(a[i]>max){ max=a[i]; } } System.out.println(max); }}
- For-Each循环
//遍历输出每一个数组元素 无下标 for(int b:a){ System.out.println(b); }
- 数组作方法入参
public static void main(String[] args) { int[] a={1,2,3,4,5,6,7,8}; arrary(a); } //打印数组 public static void arrary(int[] a){ for (int i = 0; i <a.length ; i++) { System.out.println(a[i]); } }
- 数组作返回值
//反转数组public static int[] reverse(int[] a){ int[] result=new int[a.length]; //反转的操作 for (int i = 0,j=result.length-1; i <a.length ; i++,j--) { result[j]=a[i]; } return result;}
- 完整代码
package com.company;public class Main { public static void main(String[] args) { int[] a={1,2,3,4,5,6,7,8}; arrary(a); System.out.println("=========="); //遍历输出每一个数组元素 无下标// for(int b:a){// System.out.println(b);// } // arrary(reverse(a)); } //打印数组 public static void arrary(int[] a){ for (int i = 0; i <a.length ; i++) { System.out.println(a[i]); } } //反转数组 public static int[] reverse(int[] a){ int[] result=new int[a.length]; //反转的操作 for (int i = 0,j=result.length-1; i <a.length ; i++,j--) { result[j]=a[i]; } return result; }}
多维数组
- 可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,每一个元素都是一个数组
- 二维数组
int a[][]=new int[2][5]
- 解析:以上二维数组a可以看作是一个两行五列的数组
package com.company;public class Main {public static void main(String[] args) {int[][] a={{1,2},{1,4},{1,5}};//打印数组每个元素System.out.println(a[1][1]);System.out.println(a[0][1]);System.out.println(a[1]);//打印的是一个对象,没有输出实际的值arrary(a[0]);System.out.println("=============");//打印数组中每一个元素for (int i = 0; i <a.length ; i++) {for (int j = 0; j <a[i].length ; j++) {System.out.println(a[i][j]);}}//打印数组元素}public static void arrary(int[] a){for (int i = 0; i <a.length ; i++) {System.out.println(a[i]+" ");}}
}
Arrays类
数组的工具类java.util.Arrays
由于数组对象本身没有声明方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些进本操作
查看JDK帮助文档(下载链接)
参考文章https://blog.csdn.net/qq_40147863/article/details/83051268
Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而不用使用对象来调用(是不用不是不能,这点要注意)
常用的功能
- 给数组赋值:通过fill方法
- 对数组排序:通过sort方法,按升序
- 比较数组:通过equals方法比较数组中元素值是否相等
- 查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作
package com.company;import java.util.Arrays;public class Main { public static void main(String[] args) { int[] a={1,25,23452,12,412,63,2}; Arrays.sort(a);//数组排序:升序 //Arrays.toString();打印数组元素 System.out.println(Arrays.toString(a)); Arrays.fill(a,0);//数组填充 //Arrays.fill(a,2,4,0);//在第2到第4的下标中间填充0 System.out.println(Arrays.toString(a));//输出的值都为0 }}
冒泡排序
- 最出名的排序算法之一,共有8总排序方式
- 冒泡排序代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较
- 我们看到嵌套循环,应该马上就可以得出这个算法的时间复杂度O(n2)。
package com.company;import java.util.Arrays;public class Main {public static void main(String[] args) {int[] a={1,25,23452,12,412,63,2};//sort(a);System.out.println(Arrays.toString(sort(a)));}/*冒泡排序1、比较数组中,两个相邻的元素,交换位置2、每一次比较都会产生一个最大或者最小的数3、下一轮则少一次排序4、依次循环*/public static int[] sort(int[] a) {int temp=0;//外层循环,判断要走几次for (int i = 0; i <a.length-1 ; i++) {//内层循环,比较判断两个数,交换位置for (int j = 0; j <a.length-1-i ; j++) {if (a[j+1]<a[j]){//升序//if (a[j+1]>a[j]){//降序 temp=a[j+1];a[j+1]=a[j];a[j]=temp;}}}return a;}
}
假设已经排好序了,我们就优化一下冒泡
public static int[] sort(int[] a) { int temp=0; //外层循环,判断要走几次 for (int i = 0; i <a.length-1 ; i++) { boolean flag=flase;//通过flag标识位减少没有意义的比较 //内层循环,比较判断两个数,交换位置 for (int j = 0; j <a.length-1-i ; j++) { if (a[j+1]<a[j]){//升序 //if (a[j+1]>a[j]){//降序 temp=a[j+1]; a[j+1]=a[j]; a[j]=temp; } } if(flag==false){ break; } } return a;}
稀疏数组
引入
- 需求:五子棋游戏,有存盘退出和续上盘的功能
- 分析问题:因为该二维数组的很多默认值为0,因此记录很多没有意义的数据
- 解决:稀疏数组
介绍
- 当一个数组中大部分元素为0时,或者同一值的数组时,可以用稀疏数组来保存该数组
- 处理方式
- 记录数组一共有几行几列
- 具有不用值的元素和行列值记录在一个小规模的数组中,从而缩小到程序的规模
如下
原始数组
[0 0 0 1 0 2
0 0 3 0 0 0
0 0 0 0 1 0
1 2 0 0 0 0 ]
稀疏数组
行 | 列 | 值 | |
---|---|---|---|
[0] | 共4 | 共6 | 共6 |
[1] | 0 | 3 | 1 |
[2] | 0 | 5 | 2 |
[3] | 1 | 2 | 3 |
[4] | 2 | 4 | 1 |
[5] | 3 | 0 | 1 |
[6] | 3 | 1 | 2 |
package com.company;import java.util.Arrays;public class Main {public static void main(String[] args) {int[][] a=new int[5][5];a[1][2]=1;a[2][3]=1;System.out.println("输出原始数组");for (int[] ints : a) {for(int ants:ints){System.out.print(ants+" ");}System.out.println();}//转换为稀疏数组//获取有效值个数int sum=0;for (int i = 0; i <5 ; i++) {for (int j = 0; j <5 ; j++) {if(a[i][j]!=0){sum++;}}}System.out.println("有效值个数"+sum);//创建一个稀疏数组的数组int [][] a2=new int[sum+1][3];a2[0][0]=5;a2[0][1]=5;a2[0][2]=sum;//遍历二维数组,并将非零的值,存放到稀疏数组中int count=0;for (int i = 0; i <a.length ; i++) {for (int j = 0; j <a[i].length ; j++) {if(a[i][j]!=0){count++;a2[count][0]=i;a2[count][1]=j;a2[count][2]=a[i][j];}}}//输出稀疏数组System.out.println("稀疏数组");for (int i = 0; i <a2.length ; i++) {System.out.println(a2[i][0]+"\t"+a2[i][1]+"\t"+a2[i][2]+"\t");}System.out.println("==============");System.out.println("还原");//读取稀疏数组int[][] a3=new int[a2[0][0]][a2[0][1]];//给其中的元素还原它的值for (int i = 1; i <a2.length ; i++) {a3[a2[i][0]][a2[i][1]]=a2[i][2];}//打印System.out.println("输出还原数组");for (int[] ints : a3) {for(int ants:ints){System.out.print(ants+" ");}System.out.println();}}
}
面向对象编程
什么是面向对象
面向过程思想
步骤清晰简单,第一部做什么,第二部做什么
面向过程适合处理一些简单的问题
面向对象思想
- 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对每个分类思考。最后,才会对某个分类下的细节进行面向过程的思索
- 面向对象适合处理复杂的问题,适合多人协作问题
对于描述复杂的事物,为了宏观上把握从整体上分析,我们需要使用面向对象分析整个系统。但是,具体到微观操作,仍然需要面向过程思路去处理
面向对象编程(Object-Oriented Programming,OOP)
面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据
抽象
三大特征
- 封装
- 继承
- 多态
从认识论角度考虑是现有对象后有类。对象,是具体的事务。类,是抽象的,是对对象的抽象
从代码运行角度考虑是现有类后有对象。类是对象的模板
回顾方法定义和调用
- 方法的定义
- 修饰符
- 返回类型
- break和return的区别
- 方法名
- 参数列表
- 异常抛出
package com.company;import java.io.IOException;//Main 这就是一个类
public class Main {//main方法public static void main(String[] args) {}/*修饰符 返回值类型 方法名(...){//方法体return 返回值;}*///return 结束方法,返回一个结果public String say(){return "hello";}public void kong(){return;}public int max(int a,int b){return a>b? a:b;}//数组下标越界异常public void readFile(String file)throws IOException{}
}
方法的调用
静态方法
- student类
package com.company;public class student { public static void say() { System.out.println("hello"); }}
- main调用
package com.company;public class Main { public static void main(String[] args) { student.say(); }}
非静态方法
- student类
package com.company;public class student {public void say() {System.out.println("hello");} }
- main调用
package com.company;public class Main {public static void main(String[] args) {//实例化这个类//对象类型 对象名=对象值student student=new student();student.say();} }
public class Main {public static void main(String[] args) {}//和类一起加载public static void a(){b();//因此这里会报错}//类实例化之后存在public void b(){} }
- 形参和实参
package com.company;public class Main { public static void main(String[] args) { //实际参数和形式参数对应 Main main = new Main();//用new来实例化 int a=main.add(1,2); System.out.println(a); } public int add(int a,int b){//非静态方法 return a+b; }}
值传递和引用传递
值传递
package com.company;public class Main {//值传递 public static void main(String[] args) { int a=1; System.out.println(a); Main.change(a);//调用之后但是无返回值 System.out.println(a);//值为1 } //返回值为空 public static void change(int a){ a=10; }}
引用传递
package com.company;public class Main { public static void main(String[] args) { Person person = new Person(); System.out.println(person.name); change(person); System.out.println(person.name); } public static void change(Person person){ //person是一个对象,这是一个具体的人,可以改变属性 person.name="kongkong"; }}//定义一个Person类,有一个属性:nameclass Person{ String name;//name为null}
this关键字
package com.company;public class Student { String name; int age; //方法 public void study(){ System.out.println(this.name); }}
类和对象创建
类是一种抽象的数据类型,它是对某一事物整体描述/定义,但是并不是代表某一个具体事物
- 动物、植物、手机、电脑
- Person、pet、Car类等,这些类都是用来描述/定义某一类具体事物应该具备的特点和行为
对象是抽象概念的具体实例
- 张三就是人的一个具体实例,张三家的旺财就是狗的一个具体实例
- 能够体现特点,展现出功能的是具体的实例,而不是抽象概念
创建与初始化对象
- 使用new关键字创建
- 使用new关键字创建的时候,除了分配内存空间外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用
- 类中的构造器也成为方法,是在进行创建对象的时候必须掌握要调用的,并且构造器有以下两个特点:
- 必须和类的名字相同
- 必须没有返回类型,也不能写void
Student类
package com.company;public class Student { String name; int age; //方法 public void study(){ System.out.println(this.name); }}
- 实例化classMates
package com.company;public class classMates { //类,抽象的,实例化 //类实例化后会返回抑制自己的对象! //student对象就是一个Student类的具体实例 public static void main(String[] args) { Student student = new Student(); student.name="小明"; student.age=12; System.out.println(student.name); System.out.println(student.age); }}
构造器详解(必须掌握)
一个类即使什么都不写,它也有构造方法
构造器
- 和类名相同
- 没有返回值
作用
- 实例化初始值
- 使用new关键字,必须有构造器,本质在调用构造方法
注意点
- 定义有参构造后,如果使用无参构造,显示的定义一个无参构造方法
Student类
package com.company;public class Student { //一个类即使什么都不写,都会存在一个方法 //显示的定义构造器 String name; int age; //方法 //使用new关键字,本质上在调用构造器 //用来初始化值 public Student(){ } //有参构造:一旦定义了有参构造,无参构造必须显式定义 public Student(String name){ this.name=name; }}
- 实例化
package com.company;public class classMates { //类,抽象的,实例化 //类实例化后会返回抑制自己的对象! //student对象就是一个Student类的具体实例 public static void main(String[] args) { Student student = new Student("kongkong"); System.out.println(student.name); }}
ALT+INSERT可以直接生成有参无参,或者鼠标右键生成
package com.company;public class Student {//一个类即使什么都不写,都会存在一个方法//显示的定义构造器String name;int age;public String getName() {return name;}public void setName(String name) {this.name = name;}
}}
类和对象小结
package com.company;public class classMates {/*1.类与对象类是一个模板:抽象,对象是一个具体的实例2.方法定义与调用3、对应的引用引用类型:基本类型(8)对象通过引用来操作:栈--->堆4、属性:字段filed 成员变量默认初始化:数字: 0char:u000boolean:false引用:null修饰符 属性类型 属性名=属性值5、对象的创建与使用必须使用new 关键字创造对象 构造器 Person person=new Person();对象的属性 person.name对象的方法 person.sleep6、类静态的属性 属性动态的行为 方法封装、继承、多态*/}
}
封装
该露的露,该藏的藏
我们程序设计追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合就是仅暴露少量的方法给外部使用
封装(数据的隐藏)
通常,应该禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这就称为信息隐藏
属性私有 get/set
Student类
package com.company;//类 private 私有public class Student { private String name; private int id; private char sex; private int age; public String address; //私有不能直接实例化然后点出来 //提供一些可以操作这个属性的方法 //get 获取这个值 public String getAddress() { return this.address; } //set 给这数据赋值 public void setAddress(String address) { this.address = address; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public int getId() { return this.id; } public void setId(int id) { this.id = id; } public char getSex() { return this.sex; } public void setSex(char sex) { this.sex = sex; } public int getAge() { return age; }//可以写一些方法判断封装 public void setAge(int age) { if(age>0&&age<120){ this.age = age; }else { System.out.println("年龄不合法"); } }}
- classMates
package com.company;public class classMates { /* 1、提高程序的安全性,保护数据 2、隐藏代码的实现细节 3、统一接口 4、系统可维护性增加 */ public static void main(String[] args) { Student s1 = new Student(); //s1.name 这个是不能调用方法的,因为是私有 s1.setAddress("广东省"); System.out.println(s1.getAddress());//这个是可以调用的 s1.setName("kogkong"); System.out.println(s1.getName()); s1.setAge(110); System.out.println(s1.getAge()); }}
继承
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
extends的意思是扩展。子类是父类的扩展
Java类中只有单继承,没有多继承
继承是类和类之间的一种关系。除此之外还有依赖、组合、聚合
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示
子类和父类之间,从某种意义上应该具有“is a”的关系
- Person类
package com.company;public class Person { public void say(){ System.out.println("我能行"); }}
- Student类(继承Person类)
package com.company;public class Student extends Person{}
- 主函数
package com.company;public class classMates { public static void main(String[] args) { Student s1 = new Student(); //可以看到此时的Student继承了父类的所有方法 s1.say(); }}
object类
- 在Java中,所有的类都会默认继承object类
super类
注意点
- super调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法
Vs this
代表的对象不同
this:本身调用这个对象
super:代表父类对象的调用
前提
this:没有继承也可以使用
super:只能在继承条件才能使用
构造方法
this():本类的构造
super():父类的构造
方法重写
- Person类
package com.company;public class Person { //重写都是方法的重写,和属性没有关系 public void say(){ System.out.println("我能行"); }}
- Student类(继承Person类)
package com.company;public class Student extends Person{ @Override//重写方法的注解 public void say() { System.out.println("加油,别放弃"); }}
- 主函数
package com.company;public class classMates { //静态的方法和非静态方法区别很大 //静态方法和定义的数据类型有关 //非静态方法:重写 public static void main(String[] args) { Student s1 = new Student(); s1.say(); Person s2=new Student(); s2.say(); //结果是一样的 //假设Student类没有重写,s2.say()调用Person里面的东西 }}
重写总结
需要有继承关系,子类重写父类的方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大但不能缩小
- 抛出的异常:范围,可以被缩小,但不能扩大
重写,子类的方法和父类必须保持一致:方法体不同
为什么要重写:
父类的功能,子类不一定需要,也不一定满足
override重写的注解
多态
- 即同一个方法可以根据发送对象的不同采取多种不同的行为方式
- 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多(父类,有关系的类)
- 多态的存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
- 注意 多态是方法的多态,属性没有多态性
package com.company;
//具体综合继承来思考多态
public class classMates {//一个对象的实力类型是确定的//new Student();//new Person();//可以指向的引用类型就不确定了:父类的引用指向子类//Student 能调用的方法都是自己的或者继承父类的public static void main(String[] args) {Student s1 = new Student();s1.say();//父类型,可以指向子类,但是不能调用子类独有的方法Person s2=new Student();s2.say();//对象能执行那些方法 主要看对象左边的类型,和右边关系不大//子类重写父类的方法,执行子类的方法}
}
- instanceof和类型转换
(类型转换)引用类型,判断一个对象是什么类型
- 父类引用指向子类的对象
- 把子类转换为父类,向上转型
- 把父类转换为子类,向下转型:强制转换
- 方便方法的调用,减少重复的代码!
static
package com.company;//类 private 私有public class Student extends Person{ private static int age;//非静态的变量 private double score;//静态变量 public static void main(String[] args) { Student s1 = new Student(); System.out.println(s1.age); System.out.println(s1.score); System.out.println(Student.age); //System.out.println(Student.score);//此时这个会报错 }}
静态代码块
package com.company;public class Person {//2 赋初值{System.out.println("匿名代码块");}//1 只执行一次static {System.out.println("静态代码块");}//3public Person(){System.out.println("构造方法");}public static void main(String[] args) {Person s1 = new Person();System.out.println("============");Person s2=new Person();}
}
静态导入包
package com.company;//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Person {public static void main(String[] args) {System.out.println(random());System.out.println(PI);}}
特别注意
被Final的类不能被继承
抽象类
- abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法就是抽象方法,类就是抽象类
- 抽象类中可以没有抽象方法,但是抽象方法一定要有抽象类
- 抽象类,不能直接使用new关键字来创建对象,他是用来让子类继承的
- 抽象方法,只有方法的声明,没有方法的实现,用来让子类实现
- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
- Person
package com.company;//abstract 抽象类:类extends: 单继承
public abstract class Person {//约束 有人帮我们实现//abstract 抽象方法只有方法名字,没有方法的实现public abstract void doSomething();/*1、不能new这个抽象类,只能靠子类去实现它,约束2、抽象类中可以写普通方法3、抽象方法必须写在抽象类中//抽象的抽象:约束*///思考? new,存在构造器吗//存在的意义:抽象出来提高开发效率
}
- Student
package com.company;//抽象类的所有方法,继承它的子类,都必须要实现它的方法
//除非子类也是一个抽象类,然后让子子类去写方法
public class Student extends Person{@Overridepublic void doSomething() {}
}
接口
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有
接口:只有规范!自己无法写方法
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。如果你是汽车,你必须能跑。
接口的本质是契约,就像我们人间的法律一样,制定后大家都遵循
oo的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++,Java)就是因为设计模式所研究的,实际上就是如何合理的去抽象
作用
- 约束
- 定义一些方法,让不同的人实现
- public abstract
- public static final
- 接口不能被实例化,接口没有构造器
- implements可以实现多个接口
- 必须要重写接口中的方法
事例
- StudentService
package com.company;public interface StudentService {String delete(String name);String add(String name);}
- Student
package com.company;//抽象类:extends //类 可以实现接口implements接口 //实现接口的类,就需要重写接口中的方法//多继承 public class Student implements StudentService{@Overridepublic String delete(String name) {return null;}@Overridepublic String add(String name) {return null;} }
内部类
内部类就是在一个类的内部再定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类
成员内部类
- student
package com.company;public class Student {private int id=9;public void out(){System.out.println("这是外部类方法");}public class student1{public void in(){System.out.println("这是内部类方法");}//获取外部类的私有属性public void getID(){System.out.println(id);}} }
- 调用方法
package com.company;public class classMates {public static void main(String[] args) {//外部类通过newStudent student = new Student();//通过这个外部类来实例化内部类Student.student1 student1 = student.new student1();student1.getID();}}
静态内部类
局部内部类
public class Student {private int id=9;public void out() {class student1{public void out1(){System.out.println("局部内部类");}}} }
- 匿名内部类
package com.company;public class Student {public static void main(String[] args) {new apple().eat();//没有名字的初始类,不用实力保存到变量中,节省内存} } class apple{public void eat(){System.out.println("好吃");} }
异常
什么是异常
- 实际工作中,比如说写的某一个模块,用户输入不一定符合你的要求、你的程序要打开某个文件,这个文件可能不存在或者格式不对,你读取数据可能为空,我们的程序再跑着,内存或者硬盘满了
- 软件程序运行中,遇到的哪些问题就叫做异常,英文Exception。
- 异常指程序运行中出现的各种状况,如:文件找不到、网络连接失败、非法参数
- 异常发生再程序运行期间,影响正常执行
分类
检查性异常
最代表性的检查型异常是用户或问题引起的异常,这是无法预见的
运行时异常
运行时异常可能是被程序员避免的异常,与检查性异常相反,运行时异常可以再编译时被忽略
错误
错误不是异常,他是脱离程序员控制的问题,错误代码中通常被忽略。
异常体系结构
Java把异常当作对象处理,并定义一个基类java.lang.Throwable作为所有异常的超类
再Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception
Error
- error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关
- Java虚拟机运行时报错,当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError.这些异常发生时,JVM一般选择线程终止
- 还有发生在虚拟机试图执行应用时,它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的情况
Exception
在Exception分支中有一个重要的子类
- RuntimeException(运行时异常)
- ArrayindexOutOfBoundsException(数组下标越界)
- NullPointerException(空指针异常)
- ArithmetcException(算术异常)
- MissingResourceException(丢失资源)
- ClassNotFoundException(找不到类)
这些异常不检查异常,程序中可以捕获处理或者不处理
通常是程序逻辑引起的,程序员应该从逻辑角度尽可能避免这类异常发生
Error和Exception的区别
Error通常是灾难性的致命错误,是程序无法控制和处理的,出现时,JVM一般选择终止线程;
Exception通常是可以被程序处理的并且在程序中尽可能的去处理这些异常。
异常处理机制
- 抛出异常(不处理)
- 捕获异常(要处理)
package com.company;public class Student {public static void main(String[] args) {int a=1;int b=0;//假设要捕获多个异常:从小到大try{if(b==0){throw new ArithmeticException();//主动抛出异常}System.out.println(a/b);} catch (Error e){//catch 捕获想要的异常类型System.out.println("Error");}catch (Exception e) {System.out.println("Exception");}finally {//处理善后工作System.out.println("finally");}}}
package com.company;public class Student {public static void main(String[] args) {new Student().test(1,0);}
//假设这方法处理不了异常,则可以用这种方式抛出public void test(int a,int b){if(b==0){//throwthrow new ArithmeticException();//主动的抛出异常}}
}
- 异常处理五个关键字
- try
- catch
- finally
- throw
- throws
自定义异常
- 使用Java内置的异常类可以描述在编程时出现的大部分异常,除此之外,用户还可以自定义异常,用户自定义异常,只需要继承Exception
- 在程序中使用自定义异常类,大体可以分为以下几个步骤
- 创建自定义异常
- 在方法中通过throw关键字抛出异常对象
- 如果在当前抛出异常的方法中处理异常,可以使用try-catch捕获并处理;否则在方法的声明初通过throws关键字指明要跑出给方法调用者的异常,进行下一步
- 在出现异常方法的调用这种捕获并处理异常
总结
- 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
- 在多重catch块后面,加上一个catch(Exception)来处理可能会被遗漏的异常
- 对于不确定的代码,加上try-catch,处理潜在的异常
- 切忌只是简单调用printStackTrace()去打印输出
- 具体如何操作处理异常,要根据不同的业务需求和异常类型去决定
- 尽量添加finally语句块去释放占用资源
爆肝3万5千字的Java学习笔记(超详细的java)相关推荐
- 三万五千字长文!让你懂透编译原理(六)——第六章 属性文法和语法制导翻译
三万五千字长文!让你懂透编译原理(六)--第六章 属性文法和语法制导翻译 长文预警 系列文章传送门: 万字长文+独家思维导图!让你懂透编译原理(一)--第一章 引论 万字长文!让你懂透编译原理(二)- ...
- Pandas教程【国宝级教程,一万八千字总结】
Pandas教程[国宝级教程,一万八千字总结]
- 转发——————《黄金问题3---一万五千字教你如何全面爱护你的膝盖》(正文+1楼回复必看)...
<黄金问题3---一万五千字教你如何全面爱护你的膝盖>(正文+1楼回复必看) 由 mathiasych 发表在 虎扑篮球· 健身和运动健康 http://bbs.hupu.com/fit ...
- 基于Android的漫画阅读器App设计与实现,安卓、MySQL、Java、Andriod Studio,前台用户+后台管理,完美运行,有一万五千字论文。
基于Android的漫画阅读器App设计与实现,安卓.MySQL.Java.Andriod Studio,前台用户+后台管理,完美运行,有一万五千字论文. 用户模块功能: 引导页:首先进入APP之后会 ...
- 千峰HTML5+CSS3学习笔记
千峰HTML5+CSS3学习笔记 文章目录 千峰HTML5+CSS3学习笔记 写在前面 1. 前言 2. HTML 3. CSS 3.1 选择器 3.2 CSS属性 4. 盒子模型 4.1 溢出属性 ...
- 千锋Node.js学习笔记
千锋Node.js学习笔记 文章目录 千锋Node.js学习笔记 写在前面 1. 认识Node.js 2. NVM 3. NPM 4. NRM 5. NPX 6. 模块/包与CommonJS 7. 常 ...
- 3万6千字爆肝,前端进阶不得不了解的函数式编程开发,含大量实例,手写案例,所有案例均可运行
3w6爆肝,前端进阶不得不了解的函数式编程开发,含大量实例,手写案例,所有案例均可运行 认识函数式编程 函数相关复习 函数是一等公民 高级函数 函数作为参数 案例 1,模拟 forEach 案例 2, ...
- 1万七千字精讲,JDK8 的 Lambda、Stream、LocalDate 骚技能
小Hub领读: 本篇主要讲述是 Java 中 JDK1.8 的一些新语法特性使用,主要是 Lambda.Stream 和 LocalDate 日期的一些使用讲解. 作者:虚无境 来源:cnblogs. ...
- 北大才子吴明辉3万5千字的深度分享告诉你:能成功创立秒针跟明略的连环创业者是有秘籍的
图丨明略数据.秒针系统创始人兼董事长吴明辉 [数据猿导读]千禧年,吴明辉因奥数保送北大,成为2000级数学系的一名学生:2006年创办秒针系统,奠定中国营销监测商业模式:2014年创办明略数据,带队研 ...
最新文章
- 带动画效果的卷积神经网络的讲解.pptx
- PAT甲级1043 Is It a Binary Search Tree :[C++题解]判断二叉搜索树BST、给定前序序列和中序序列
- 【云原生AI】Fluid + JindoFS 助力微博海量小文件模型训练速度提升 18 倍
- QT绘制变焦线(Zoom Line)
- 单片机原理及其应用——单片机定时器中断实验(八段数码管依次显示0~9数字)
- centos 6.7 mysql rpm_CentOS 6.7 下RPM方式安装MySQL 5.6
- 在SQL Server2005中使用 .NET程序集
- datastage 函数_DataStage常用函数大全
- [转]ASP中ActiveX控件的内嵌及调用
- android涂鸦板保存功能,android实现涂鸦,保存涂鸦后的图片,清屏
- 电脑操作精典密笈60式
- 【线程安全】—— 单例类双重检查加锁(double-checked locking)
- Codeforces Round #468 (Div. 2): E. Game with String
- 25个深度学习开源数据集
- Operation not applicable
- 阀体端面钻6孔组合机床设计及夹具设计
- 20170330今日头条笔试题
- 如何求解最大公约数和最小公倍数
- 博客广告 何乐而不为?
- 手机共享计算机网络连接,如何将手机wifi网络通过USB共享给电脑?教您共享方法...