前言
`
本文章是自学Java的一些笔记,希望能够帮助到更多想学习Java的小伙伴!如有不对的地方欢迎多多评论,互相讨论,互相学习。
一、Java基础语法
1.注释
-
我们编写代码,在代码量少的时候,还能看懂自己写的,但是当项目结构复杂起来,我们就需要用到注释了。
-
注释并不会被执行,是我们写代码的人看的。
-
书写注释是一个非常好的习惯
-
Java中的注释有三种:
- 单行注释
//单行注释
- 多行注释
/* 多行注释 可以注释一段文字 */
- 文档注释
/** *文档注释,自带多个参数信息 * @author yxf * @deprecated 描述 * @param 参数名 * @return 返回值情况 * @version 版本号 */
2.标识符
- 关键字(图片来源:西部开源)
- Java所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
标识符注意点:
- 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始。
- 首字符之后可以是字母 (A-Z 或者 a-z),美元符($)、或者下划线(_)或数字的任何字符组合。
- 不能使用关键字作为变量名或方法名。
- 标识符是大小写敏感的。
- 合法标识符举例:age、$salary、_value、__1_value。
- 非法标识符举例:123abc、-salary、#abc。
- 可以使用中文命名,但一般不建议这样去使用,也不建议使用拼音。
3.数据类型
- 强类型语言
1. 要求变量的使用要严格符合规定,所有变量都必须定义后才能使用。 - 弱类型语言
- Java的数据类型分为两大类
- 基本类型(primitive type)
- 引用类型(reference type)
1. 类
2. 接口
3. 数据
4.类型转换
- 由于java是强类型语言,所以要进行有些运算的时候需要用到类型转换。
低--------------------->高
byte short char -> int -> long -> float -> double
- 运算中,不同类型的数据先转化为同一类型,然后再进行运算。
- 强制类型转换。
- 自动类型转换。
/**
* @Author yxf
*/
public static void main(String[] args) {
//强制转换(类型)变量名 高到低
int i = 128;
byte b = (byte) i; //注意内存溢出
System.out.println(i +" === "+ b);
//自动转换 低到高
int ii = 128;
double d = i;
System.out.println(ii +" === "+d);
/*
注意点:
1.不能对布尔值进行转换。
2.不能把对象类型转换为不想干的类型。
3.在把高容量转换到低容量的时候,强制转换。
4.转换的时候可能会存在内存溢出,或者精度问题。
*/
System.out.println((int)23.7); //23 强制转换会存在精度问题
System.out.println((int)-45.89f);//-45
System.out.println("================");
char c = 'a';
int i1 = c+1;
System.out.println(i1);
System.out.println((char)i1);
}
//推展
public static void main(String[] args) {
//操作比较大的数的时候,注意溢出问题
//JDK7新特性,数字之间可以用下划线分割
int money = 10_0000_0000;
int years = 20;
int total = money*years;//-1474836480,计算的时候溢出了
long total1 = money*years;//-1474836480,默认是int,转换之前已经存在问题了
long total2 = money*(long)years;//先把一个数转换为long
System.out.println(total2);
}
5.变量、作用域、常量
变量
- 变量:就是可以变化的量。
- java是一种强类型语言,每个变量都必须声明类型。
- java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域。
注意事项:
-
每个变量都有类型,类型可以是基本类型,也可以是引用类型。
-
变量名必须是合法的标识符。
-
变量声明是一条完整的语句,因此每一个声明都必须以分号结束。
类的作用域
- 类变量
- 实例变量
- 局部变量
/**
* @Author yxf
*/
static int age = 25; //类变量
//实例变量从属于对象;如果不自行初始化,这个类的默认值 0 0.0
// boolean false
// 除了基本类型,其余默认值都是null
String name = "shaking"; //实例变量
public int getInfo(){
int sex = 1; //局部变量
return sex;
}
public void add(){
String name1 = "xky"; //局部变量 : 必须声明和初始化值
}
public static void main(String[] args) {
Demo3 demo3 = new Demo3();
int a = demo3.getInfo();
demo3.add();
System.out.println(demo3.name+"==="+age+"==="+a);
}
常量
- 常量:初始化后不能再改变值!不会变动的值。
- 所谓常量可以理解成一种特殊的变量,它的值被设定后,在程序运行过程中不允许被改变。
- 常量名一般使用大写字符。
//static(修饰符,不存在先后顺序)
static final int PID = 12345678;
public static void main(String[] args) {
System.out.println(PID);
}
变量的命名规范
- 所有的变量、方法、类名:见名知意。
- 类成员变量:首字母小写和驼峰原则:monthSalary。
- 局部变量:首字母小写和驼峰原则。
- 常量:大写字母和下划线:MAX_VILUE。
- 类名:首字母大写和驼峰原则:Max,GoodMan。
- 方法名:首字母小写和驼峰原则:run(),getRun()。
6. 运算符
java语言支持如下运算符:
-
算术运算符:+、-、*、/、%、++、–。
-
赋值运算符: =。
-
关系运算符:> 、< 、>=、 <= 、==、 !=、 instanceof。
-
逻辑运算符:&& 、||、!。
-
位运算符:&、|、^ 、~、>> 、<< 、>>>。
-
条件运算符: ?:。
-
扩展赋值运算符:+=、-=、*=、/=。
- 二元运算符
/**
* @Author yxf
*/
public static void main(String[] args) {
//二次运算符
//操作中有一个为long类型,那输出的结果就为long
//如果没有long就是int
//如果有double就是double
double a = 22.0;
int b = 123;
short c = 25;
byte d = 8;
System.out.println(a+b+c+d); //long/double
System.out.println(b+c+d); //int
System.out.println(c+d); //int
}
- 关系运算符
/**
* @Author yxf
*/
public static void main(String[] args) {
//关系运算符返回的结果:正确,错误,boolean
int a = 10;
int b = 20;
int c = 33;
System.out.println(a==b); //false
System.out.println(a>b); //false
System.out.println(a<b); //true
System.out.println(a!=b); //true
System.out.println(c%a); //3 取余,模运算 (c/a 33 / 10 = 3.3取余数)
}
- 一元运算符
/**
* @Author yxf
*/
public static void main(String[] args) {
//++自增 -- 自减 一元运算符
int a = 3;
System.out.println(a+"===");
// a = a + 1;
int b = ++a; //执行完这行代码前,先自增,再赋值给a
int c = a++; //执行完这行代码后,先给c赋值,再自增
// a = a + 1;
System.out.println(a);
System.out.println(b);
System.out.println(c);
//幂运算 3^2 3*3 = 8 很多运算,我们会使用一些工具类来操作!
double pow = Math.pow(3,2);
System.out.println(pow);
}
- 逻辑运算符
/**
* @Author yxf
*/
public static void main(String[] args) {
//与(and) 或(or) 非(取反)
boolean a = true;
boolean b = false;
//逻辑与运算:两个变量都为真,结果才为true
System.out.println("a&&b:"+(a&&b));
//逻辑或运算:两个变量有一个为真,则结果为true
System.out.println("a||b:"+(a||b));
//如果是true,则变为false,如果是false则变为true
System.out.println("a&&b:"+!(a&&b));
//短路运算
int c = 5;
//&& 如果前面的条件为false,那后面的条件不会执行。
boolean d = (c < 4)&&(c++ < 4);
System.out.println(d); //false
System.out.println(c); //5
}
- 位运算
/**
* @Author yxf
*/
public static void main(String[] args) {
/*
A = 0011 1100
B = 0000 1101
-------------------
如果A和B的对应位都是1,结果就是1,否则为0
A&B = 0000 1100
如果A和B的对应位都是0,结果就是0,否则为1
A/B = 0011 1101
如果这两个位置相同,则为0,否则为1
A^B = 0011 0001
取反
~B = 1111 0010
2*8 = 16 2*2*2*2
效率极高!!!
<< 左移 *2
>> 右移 /2
0000 0000 0
0000 0001 1
0000 0010 2
0000 0011 3
0000 0100 4
0000 1000 8
0001 0000 16
*/
//2<<6 2*2的6次方 2*2*2*2*2*2
System.out.println(2<<6);
//4*2的3次方 4*4*4
System.out.println(4<<3);
}
- 扩展运算符
/**
* @Author yxf
*/
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);
//字符串链接符 + ,String
System.out.println("==="+a+b); //===1020
System.out.println(a+b+"==="); //30===
}
- 三元运算符
public static void main(String[] args) {
int score = 80;
//三元运算符 x ? y : z 如果为true,则返回y,否则返回z
String type = score < 60 ? "不及格" : "及格";
System.out.println(type);
}
二、Scanner与流程控制
1. Scanner对象
- 基本语法
Scanner scanner = new Scanner(System.in);
- 通过Scanner类的next() 与 nextLine()方法获取输入的字符串,在读取前我们一般需要使用hasNext()与hasNextLine()判断是否还有输入的数据。
/**
* @Author yxf
*/
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);
}
//凡是属于IO流的类,如果不关闭会一直占用资源,要养成好习惯用完就关掉
scanner.close();
}
-
Next()
- 一定要读取到有效字符后才可以结束输入。
- 对输入有效字符之前遇到的空白,next()方法会自动将其去掉。
- 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
- next()不能得到带有空格的字符串。
-
nextLine()
- 以enter为结束符也就是说nextLine()方法返回的是输入回车之前的字符。
- 可以获得空白。
/**
* @Author yxf
*/
public static void main(String[] args) {
//我们可以输入多个数字,并求其总和与平均数,每输入一个数字用会车确认
Scanner scanner = new Scanner(System.in);
//和
double sum = 0;
//计算输入了多少个数字
int m = 0;
//通过输入非数字来结合输入并输出执行结果
while (scanner.hasNextDouble()){
double x = scanner.nextDouble();
m = ++m;
sum = sum + x;
System.out.println("你输入了第"+m+"个数据,然后当前结果sum="+sum);
}
System.out.println(m + "个数的和为" + sum);
System.out.println(m + "个数的平均值是" + (sum / m));
scanner.close();
}
2. 流程控制
- 顺序结构
- java的基础结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行。
- 顺序结构是最简单的算法结构。
- 语句与语句之间,框与框之间是按照从上到下的顺序进行的,它是由若干个依次执行的处理步骤组成的,它是任何一个算法都离不开的一种基本算法结构。
3.If选择结构
1. If单选择结构
- 我们很多时候需要去判断一个东西是否可行,然后我们才去执行,这样一个过程在程序中用if语句来表示。
- 语法
if(布尔表达式){
//如果布尔表达式为true将执行的语句
}
- 练习案例
/**
* @Author yxf
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容:");
String str = scanner.nextLine();
if(str.equals("hello")){
System.out.println(str);
}
System.out.println("End");
scanner.close();
}
2. If双选择结构
- 那现在有个需求,公司要收购一个软件,成功了,给人支付100万元,失败 了骂自己找人开发。这样的需求用if就搞不定了,我们需要两个判断,需要一个双选择结构,所以就有了if-else结构。
- 语法
if(布尔表达式){
//如果布尔表达式为true将执行的语句
}else{
//如果布尔表达式为false将执行的语句
}
- 练习案例
/**
* @Author yxf
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("软件是否收购成功?(yes/no)");
String yn = scanner.nextLine();
if(yn.equals("yes")){
System.out.println("支付100万!");
}else {
System.out.println("自己开发!");
}
System.out.println("End");
scanner.close();
}
3. If多选择结构
- 我们发现刚才的代码不符合实际情况,真实的情况还可能存在ABCD,存在区间多级判断。比如90-100就是A,80-90就是B…等等,再生活中我们很多时候的选择也仅仅只有两个,所以我们需要一个多选择结构来处理这类问题!
- 语法
if(布尔表达式 1){
//如果布尔表达式 1为true将执行的语句
}else if(布尔表达式 2){
//如果布尔表达式 2为true将执行的语句
}else if(布尔表达式 3){
//如果布尔表达式 3为true将执行的语句
}else{
//如果布尔表达式为false将执行的语句
}
- 练习案例
/**
* @Author yxf
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入分数:");
float score = scanner.nextFloat();
/*
if 语句至少有一个else语句,else语句在所有的else if语句之后。
if 语句可以有若干个else if 语句,它们必须在else 语句之前。
一旦其中一个else if 语句检测为true,其他的else if 以及else语句都将跳过执行。
*/
if(score == 100){
System.out.println("优秀学生!");
}else if (score >= 80 && score <=100){
System.out.println("A等级!");
}else if(score >= 60 && score <=70){
System.out.println("B等级!");
}else if (score >= 0 && score <=60){
System.out.println("不及格!继续加油!");
}else {
System.out.println("成绩不合法!");
}
System.out.println("End");
scanner.close();
}
4. 嵌套的if结构
- 使用嵌套的if…else语句是合法的,也就是说你可以在另一个if或者else if语句中使用if 或者else if 语句。你可以像if 语句一样嵌套else if… else。
- 语法
if(布尔表达式 1){
//如果布尔表达式 1为true将执行的语句
if(布尔表达式 2){
//如果布尔表达式 2为true将执行的语句
}
}
- 练习案例
/**
* @Author yxf
*/
public static void main(String[] args) {
//我们需要寻找一个数,在1-100之间
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字:");
int x = scanner.nextInt();
if(x <= 50){
if(x <= 100){
System.out.println("数字在50-100之间");
}else {
System.out.println("数字大于100");
}
}else {
System.out.println("数字小于50");
}
System.out.println("End");
scanner.close();
}
4.switch多选择结构
- 多选择结构还有一个实现方式就是switch case语句。
- switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
- switch 语句中的变量类型可以是:
- byte、short、int或者char。
- 从java SE 7 开始。
- swinch 支持字符串String类型。
- 同时case标签必须为字符串常量或字面量。
1. break关键字
- break关键字可以用在switch中,一旦执行,整个switch将立刻结束。
- break关键字也可以用在其他语句中,整个循环语句立刻结束,打断循环。
2. default关键字
- default的作用是在case匹配失败之后才会被执行,打印出来相对应的输出信息。
3. continue关键字
-
contine关键字立即跳过本次的循环,进入到下一个循环语句当中
-
练习案例
/**
* @Author yxf
*/
public static void main(String[] args) {
String str = "shaking";
switch (str){
case "shaking":
System.out.println("shaking===");
break;
case "xky":
System.out.println("xky===");
break;
case "谢可寅":
System.out.println("谢可寅===");
break;
default:
System.out.println("什么啊!");
}
}
5.循环结构
1.while循环
-
while循环是最基本的循环,它的循环结构为:
-
语法
while(布尔表达式){
//循环内容
}
-
只要布尔表达式为true,循环就会一直执行下去。
-
我们大多数情况是会让循环停止下来的,我们需要一个让表达式失效的方式来结束循环。
-
少部门情况需要循环一直执行,比如服务器的请求响应监听等。
-
循环条件一直为true就会造成无限循环(死循环),我们正常的业务编程中应该尽量避免死循环。会影响程序性能或者造成程序卡死崩溃!
-
练习案例
/**
* @Author yxf
*/
public static void main(String[] args) {
//输出1-100,并求出总和
int i = 0;
int sum =0;
//只要满足表达式条件就会执行while循环,一旦不满足就会终止。
while (i <= 100){
sum = sum + i;
i++;
System.out.println("运行第 "+i+" 次");
}
System.out.println("总和为:" + sum);
}
2.do…while循环
- 对于while语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。
- do…while循环和while循环相似,不同的是,do…while循环至少会执行一次。
- 语法
do{
//代码语句
}while(布尔表达式);
- 练习案例
public static void main(String[] args) {
//求1+2+3+4+5+...100 = ?
int i = 0;
int sum =0;
//只要满足表达式条件就会执行while循环,一旦不满足就会终止。
do {
sum = sum + i;
i++;
} while (i <= 100);
System.out.println("总和为:" + sum);
}
- while和do…while的区别:
- while先判断后执行。do while是先执行后判断!
- do while总是保证循环体会被至少执行一次!这是它们之间的主要差别。
6.while 和 do while的区别案列
/**
* @Author yxf
*/
public static void main(String[] args) {
int i = 0;
while (i < 0){
i++;
System.out.println(i+" shaking");
}
do {
i++;
System.out.println(i+" xky");
}while (i < 0);
}
3.For循环(重点!!!)
- 虽然所有循环结构都可以用while或者do while表示,但Java提供了另一个语句 —— for循环,使一些循环结构变得更加简单。
- for循环语句是支持迭代的一种通用结构,是最有效,最灵活的循环结构。
- for循环执行的次数是在执行前就确定的,语法或者如下:
for(初始化;布尔表达式; 更新){
//代码语句
}
- 练习案例1:
public static void main(String[] args) {
// i初始化值 // 判断条件 //迭代
for (int i = 0; i <= 100; i++) {
System.out.println(i);
}
/*
关于for循环有一下几点说明:
最先执行初始化步骤,可以声明一种类型,但可初始化一个或者多个循环控制变量,也可以是空语句。
然后,检测布尔表达式的值,如果为true,则循环被执行,如果为false,循环终止,开始执行循环体后面的语句。
执行一次循环后,更新循环控制变量(迭代因子控制循环的增减)。
再次检测布尔表达式,循环执行上面的过程。
*/
//死循环
for (; ; ) {
}
}
- 练习案例2:计算0到100之间的奇数和偶数的和。
/**
* @Author yxf
*/
public static void main(String[] args) {
//计算0到100之间的奇数和偶数的和。
int oddSum = 0; //奇数和
int evenSun = 0; //偶数和
for (int i = 0; i <= 100; i++) {
if (i%2!=0){
oddSum += i; // oddSum = oddSum + i
}else {
evenSun += i;
}
}
System.out.println("奇数总和:"+oddSum);
System.out.println("偶数总和:"+evenSun);
}
- 练习案例3:用while或for循环输出1-1000之间被5整除的数,并且每一行输出3个。
public static void main(String[] args) {
//用for循环输出1-1000之间被5整除的数,并且每一行输出3个。
for (int i = 0; i < 1000; i++) {
if(i % 5 == 0){
System.out.print(i+"\t");
}
if(i % (5 * 3) == 0){//每行
System.out.println();
}
}
}
- 练习案例4:打印九九乘法表。
/**
* @Author yxf
*/
public static void main(String[] args) {
//打印九九乘法表
/*
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
*/
//1.先打印第一列
//2.把固定的1再用一个循环包起来
//3.去掉重复项
//4.调整样式
for (int k = 1; k <= 9; k++) {
for (int i = 1; i <= k; i++) {
System.out.print(i+ "*" + k + "=" + k * i + "\t");
}
System.out.println();
}
}
4.增强for循环
- java5引入了一种主要用于数组或集合的增强型for循环。
- 语法
for(声明语句 : 表达式){
//代句子
}
- 声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定再循环语句块,其值与此时数组元素的值相等,
- 表达式:表达式是要访问的数组名,或者是返回值为数组的方法。
- 练习案例
/**
* @Author yxf
*/
public static void main(String[] args) {
int[] numbers = {5,10,20,30,35};
//遍历数组的每个元素
for (int i: numbers) {
System.out.println(i);
}
System.out.println("***shaking***");
//用for循环实现
for (int i = 0; i < 5; i++) {
System.out.println(numbers[i]);
}
}
三、方法的定义和调用
什么是方法?
- Java方法是语句的集合,它们在一起执行一个功能。
1. 方法是解决一类问题的步骤的有序组合。
2. 方法包含于类或对象中。
3. 方法在程序中被创建,在其他地方被引用。 - 设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只能完成一个功能,这样利于我们后期扩展。
1.方法的定义
-
Java的方法类似于其它语言的函数,是一段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法:
- 方法包含一个放大头和一个方法体。下面是一个方法的所有部分:
1. 修饰符:修饰符,这是可选的,告诉编译器如何调用该方法,定义了该方法的访问类型。
2. 返回值类型:方法可能会有返回值,returnValueType是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType的关键字是void。
3. 方法名:是方法的实际名称,方法名和参数表共同构成方法签名。
4. 参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实惨或变量。参数列表是指方法的参数类型、顺序和参数的个数,参数是可选的,方法可以不包含任何参数。
1. 形式参数:在方法被调用时用于接收外界输入的数据。
2. 实参:调用方法时实际传给方法的数据。
5. 方法体:方法体包含具体的语句,定义该方法的功能。
- 方法包含一个放大头和一个方法体。下面是一个方法的所有部分:
-
语法
修饰符 返回值类型 方法名(){
.....
方法体
.....
return 返回值;
}
2.方法调用
- 调用方法:对象名.方法名(实参列表)。
- Java支持两种调用方法的方式,根据方法是否返回值来选择。
- 当方法返回一个值的时候,方法调用通常被当作一个值。例如:
int larger = max(10,20);
- 如果方法返回值是void,方法调用一定是一条语句
System.out.println("Hello,shaking");
3.方法的重载(重点!!!)
-
重载就是在一个类中,有相同的函数名称,但行参不同的函数。
-
方法的重载的规则:
1. 方法名称必须相同。
2. 参数列表必须不同(个数不同或数据类型不同,参数排列顺序不同等)。
3. 方法的返回类型可以想通也可以不相同。
4. 仅仅返回类型不同不足以成为方法的重载。 -
实现理论:
1. 方法名称相同时,编译器会根据调用方法的参数个数,参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
4.可变参数
- JDK1.5开始,Java支持传递同类型的可变参数给一个方法。
- 在方法声明中,在制定参数类型后面加一个省略号(…)。
- 一个方法中只能定义一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
- 练习案例:
public static void main(String[] args) {
test(1.3,2,3,10,8,7,9);
}
public static void test(double k,int... x){
for (int i = 0; i < x.length; i++) {
System.out.println(x[i]+"是可变参数");
}
System.out.println(k+"是普通参数");
}
四、数组
1. 什么是数组
- 数组是想通类型数据的有序集合。
- 数组描述的是想通类型的若干个数据,按照一定的先后次序排列组合而成。
- 其中每一个数据称作一个数组元素,每个数组元素恶意通过一个下表来访问它们。
2.数组声明创建
- 首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
dataType[] arrayRefVar; //首选的方法
或
dataType[] arrayRefVar[]; //效果相同,但不是首选方法
- Java语言使用new操作符来创建数组,语法如下:
dataType[] arrayRefVar = new dataType[arraySize];
- 数组的元素是通过索引访问的,数组索引从0开始。
- 获取数组长度:
arrays.length
1.内存分析
- Java内存分析:
- 写代码画图分析内存
下标从0开始,如果是输出第十一个数值的时候会出现一个错误java.lang.ArrayIndexOutOfBoundsException: 10,也就是数组下标越界的情况。
2.三种初始化状态
- 静态初始化
int[a] = {2,3,1};
Man[] mans = {new Man(1,1),new Man(2,2)};
- 动态初始化
int[] a = new int [2];
a[0] = 1;
a[1] = 2;
-
数组的默认初始化
1. 数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照案例变量同样的方式被隐式初始化。 -
使用动态初始化数组的时候,其中的元素都会存在一个默认值,其默认规则如下所示:
(静态初始化也有默认值的过程,只不过系统自动马上将默认值替换为了大括号当中的具体数值)
默认规则
/**
* @author yxf
*/
public static void main(String[] args) {
//静态初始化:创建 + 赋值
int[] a = {1,2,3,4,5,6,7};
System.out.println(a[0]+"===");
//动态初始化:包含默认初始化
int[] b = new int[10];
b[0] = 10;
b[1] = 20;
System.out.println(b[0]); //输出10
System.out.println(b[1]); //输出20
System.out.println(b[2]); //输出0
}
3.数组的四个基本特点
- 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
- 其元素必须是想通类型,不允许出现混合类型。
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型。
- 数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其它对象类型,数组对象本身是在堆中的。
小结:
- 数组是相同数据类型(数据类型可以为任意类型)的有序集合。
- 数组也是对象。数组元素相当于对象的成员变量。
- 数组长度是确定的,不可变的。如果越界,则报:ArrayIndexOutOfBounds。
4.数组的使用
for each(增强for循环)
/**
* @author yxf
*/
public static void main(String[] args) {
int[] x = {0,2,80,20,30};
//打印全部数组元素
for (int a:x) {
System.out.println(a);
}
//计算所有元素的和
int sum = 0;
for (int a:x) {
sum = sum + a;
}
System.out.println("总和为:"+ sum );
//查找最大元素
int max = 0;
for (int s:x) {
if(s >= max){
max = s;
}
}
System.out.println("最大数为:"+max);
}
- 数组做方法入参
/**
* @author yxf
*/
public static void main(String[] args) {
int[] x = {0,2,80,20,30};
printArray(x);
}
//打印数组元素的方法
public static void printArray(int[] arrays){
for (int i = 0; i < arrays.length; i++) {
System.out.println(arrays[i] + " ");
}
}
- 数组做返回值
/**
* @author yxf
*/
public static void main(String[] args) {
int[] x = {0,2,80,20,30};
printArray(reverse(x));
}
//反转数组
public static int[] reverse(int[] arrays){
int[] result = new int[arrays.length];
//反转操作
for (int i = 0,j=result.length-1; i < arrays.length; i++,j--) {
result[j] = arrays[i];
}
return result;
}
//打印数组元素的方法
public static void printArray(int[] arrays){
for (int i = 0; i < arrays.length; i++) {
System.out.println(arrays[i] + " ");
}
}
3.多维数组
- 多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组。
- 二维数组
int a[][] = new int[2][5];
- 解析:以上二维数组 a 可以看成一个两行五列的数组。
- 多维组的使用:
/**
* @author yxf
*/
public static void main(String[] args) {
//int[] x = {10,2,5};
int[][] array = {{10,2},{7,3},{11,5},{18,8},{19,9}};
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.println(array[i][j]);
}
}
printArray(array[2]);
}
//打印数组元素的方法
public static void printArray(int[] arrays){
for (int i = 0; i < arrays.length; i++) {
System.out.println(arrays[i] + "===");
}
}
4.Arrays类讲解
- 数组的工具类java.util.Arrays。
- 由于数组对象本身并没有什么方法可以供我们调用,但Api中提供了一个工具类Arrays供我们使用,从而可以堆数据对象进行一些基本操作。
- 查看JDK帮助文档
- Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而不用使用对象来调用(注意:是“不用”而不是“不能”)。
- 具体以下常用功能:
1. 给数组赋值:通过fill方法。
2. 对数组排序:通过sort方法,按升序。
3. 比较数组:通过equals方法比较数组中元素是否相等。
4. 查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作。
/**
* @author yxf
*/
public static void main(String[] args) {
int[] arr = {1,33,55,66,88,2,3,8,7};
System.out.println(arr); //[I@29453f44 哈希code
//打印数组元素Arrays.toString
System.out.println(Arrays.toString(arr));
Arrays.sort(arr); //数组进行排序:升序
System.out.println(Arrays.toString(arr)); // 输出结果:[1, 2, 3, 7, 8, 33, 55, 66, 88]
Arrays.fill(arr,0,3,5); //填充数据,val:要储存在数组的所有元素中的值
System.out.println(Arrays.toString(arr));
//printArray(arr);
}
//模仿Arrays.toString实现打印数组元素的方法
public static void printArray(int[] arr){
for (int i = 0; i < arr.length; i++) {
if (i == 0) {
System.out.print("[");
}
if (i == arr.length - 1) {
System.out.print(arr[i] +"]");
} else {
System.out.print(arr[i] + ", ");
}
}
}
5.冒泡排序(重点)
- 冒泡排序无疑是最为出名的排序算法之一,总共有八大排序!
- 冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较。
- 我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为0(n2)。
/**
* @author yxf
*/
public static void main(String[] args) {
int[] array = {1,5,4,6,8,3,7,2,9};
sort(array);
System.out.println(Arrays.toString(array));
}
//冒泡排序
//1. 比较数组中,两个相邻的元素,如果第一个比第二个数大,我们就交换它们的位置;
//2. 每一次比较,都会产生出一个最大或者最小的数字;
//3. 下一轮则可以少一次排序!
//4. 一次循环,直到结束!
public static int[] sort(int[] array){
int temp = 0; //临时变量
//外层循环,判断我们这个要走多少次
for (int i = 0; i < array.length-1; i++) {
boolean flag = false; //通过flag表示位减少没有意义的比较
//内层循环,比较判断两个数,如果第一个数比第二个数大,则交换位置
for (int j = 0; j < array.length-1-i; j++) {
if(array[j+1] < array[j]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
flag = true;
}
}
if(flag == false){
break;
}
}
return array;
}
五、什么是面向对象
面向对象的方法主要是把事物给对象化,包括其属性和行为。面向对象编程更贴近实际生活的思想。总体来说面向对象的底层还是面向过程,面向过程抽象成类,然后封装,方便使用就是面向对象,(万物皆对象)。
- 面向对象编程(Object-Oriented Programming, OOP)。
- 面向对象编程的本质:以类的方式组织代码,以对象的组织(封装)数据。
- 抽象:编程思想!持续的学习,茅塞顿开!多实践,多测试大脑中的想法!时间出真知!
- 三大特性:
1. 封装
2. 继承
3. 多态 - 从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象。
- 从代码运行角度考虑是先有类后有对象。类是对象的模版。
1.类与对象的关系
- 类是一种抽象的数据类型,它是对某一个类事物整体描述/定义,但是并不能代表某一个具体的事物。
例如:手机,电脑等等;又比如Person类、Pet类、Cat类等等。 - 对象是抽象概念的具体实例。
1. 对象是抽象的具体实例。比如张三是人的一个具体实例,旺财是一个狗的具体实例。
2. 能够体现出特点,展现出功能的具体实例,而不是一个抽象的概念。
2.创建与初始化对象
- 使用new关键字创建对象。
- 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
- 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:
1. 必须和类的名字相同。
2. 必须没有返回类型,也不能写void。 - 构造器必须要掌握。
创建对象
/**
* @author yxf
*/
//学生类
public class Student {
//属性:字段
String name; //没有赋值,初始化值是null
int age; //初始化值是0
String sex;
public void study(){
System.out.println(name+"正在练习vocal");
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
//类:抽象的,实例化
//类实例化会返回一个自己的对象!
//student对象就是一个student类的具体实例!
//xky和yy就是student的对象名,名字是自己随便取的
Student xky = new Student();
xky.name = "shaking";
xky.age = 3;
xky.sex = "女";
System.out.println(xky.name+"正在练习rap");
Student yy = new Student();
yy.name = "yuYan";
yy.age = 3;
yy.sex = "女";
yy.study(); //调用Student对象里的study方法
}
}
3.构造器详解
1.什么是构造器
类中的构造器也叫构造方法,在进行创建对象的时候必须进行调用。并且每一个类中都隐藏一个无参构造。
-
构造器:
1. 和类名相同。
2. 没有返回值。 -
作用:
1. new本质是在调用构造方法。
2. 初始化对象的值。 -
注意点
1. 定义有参构造之后,如果想使用无参构造,显示的定义一个无参的构造。
/**
* @author yxf
*/
public class Person {
//一个类即使什么都不写,它也会存在一个方法
//显示的定义构造器
String name;
//实例化初始值
//1.使用new关键字,本质是在调用构造器
public Person(){
this.name = "shaking chloe";
}
//有参构造:一旦定义了有参构造,无参就必须显示定义
public Person(String name){
this.name = name;
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
//new 实例化一个对象
Person shaking = new Person("xky"); //有参构造
Person yy = new Person(); //无参构造
System.out.println(shaking.name);
System.out.println(yy.name);
}
}
2.创建对象内存分析
-
首先先在方法区把Demo01类的游戏额代码信息放进来。
1. 首先先在方法区把Demo01类的游戏额代码信息放进来。
2. 主方法main()会被压入栈.。
2. 一旦new会在方法区加载出Student这个类。
3. 当等于通过Students A= new Students();生成一个A同学放入栈中(此时的A只是一个引用或者变量名)。
4. 针对于这个对象A会在堆里面,通过这个模板new了一个A。
5. 此时的action()方法其实调用了方法区中的action()方法,此时Students A= new Students();方法就完成了。
6. 接下来给name、age进行赋值。
7. 将方法区的Demo01中的常量池中的值丢个堆中A进行name和age的赋值,此时A.name = “代码贩子、”; A.age = 24;以及A.action();中的值就赋完了,此时这个对象A的堆中就有这些值了,此时就可以使用它了。
8. 如果出现了同学B就相当于当等于通过Students A= new Students();生成一个A同学放入栈中(此时的A只是一个引用或者变量名)。
9. 针对于这个对象A会在堆里面,通过这个模板new了一个B。
10. 此时的action()方法其实调用了方法区中的action()方法,此时Students。 B= new Students();方法就完成了,此时后面的操作相同。 -
注意:静态方法区所有带static关键字的东西一开始就在这个地方,和类一起加载的,类一加加载,它就加载了。所有的对象都可以加载它
(图片来源:西部开源)
3.简单小结类与对象
- 类与对象
类是一个模版:抽象,对象是一个具体的实例。 - 方法
定义,调用! - 对应的引用
引用类型: 基本类型(8)。
对象是通过引用来操作的:栈—>堆 - 属性:字段field 成员变量
默认初始化:
数字: 0 0.0
char:u0000
boolean: false
引用:null
修饰符 属性类型 属性名 = 属性值! - 对象的创建和使用
* 必须使用new关键字创建对象,构造器Person shaking = new Person();
* 对象的属性 shaking.name
* 对象的方法 shaking.sleep(); - 类:
静态的属性 属性
动态的行为 方法
六、封装、继承、多态(重点!!!)
1.封装
- 该露则露,该藏则藏
1. 我们程序设计要追求**“高内聚,低耦合”**,高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。 - 封装(数据的隐藏)
2. 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。 - 记住这句话就够了:属性私有,get/set
/**
* @author yxf
*/
//学生类
public class Student {
//属性私有 private:私有
private String name;
private int age;
private char sex;
//提供一些可以操作这个属性的方法!
//提供一个public的get和set方法
//get 获得这个数据
public String getName() {
return name;
}
//set 给这个数据设置值
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 110 || age < 0){
this.age = 3;
}else {
this.age = age;
}
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
/*
1.提高程序的安全性,保护数据
2.隐藏代码的实现细节
3.统一接口
4.系统可维护增加了
*/
Student student = new Student();
student.setName("shaking");
System.out.println(student.getName());
student.setAge(555); //不合法的
System.out.println(student.getAge());
}
}
2.继承
- 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
- extends的意思是“扩展”。子类是父类的扩展。
- Java中类只有单继承,没有多继承!
- 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
- 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,关键字extends来表示。
- 子类和父类之间,从意义上讲应该具有“is a”的关系。
/**
* @author yxf
*/
//Person人:父类
public class Person {
//public 公共的
//protected 受保护的
//default 默认的
//private 私有的
private int money = 10_0000_0000;
public String name;
public void say(){
System.out.println("说了一段rap");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
//Teacher:子类,继承了Person父类
public class Teacher extends Person{
}
/**
* @author yxf
*/
//Student:子类,继承了父类Person
//子类也可以拥有属于自己的方法
public class Student extends Person{
public String name;
public void study(){
System.out.println("学习了一段rap");
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
Teacher teacher = new Teacher();
teacher.name = "shaking chloe";
System.out.print(teacher.name);
teacher.say();
Student student = new Student();
student.name = "xky";
System.out.print(student.name);
student.study();
System.out.println(student.getMoney());
}
}
-
修饰符的级别(由大到小):public>protected>default(不写默认就是default)>private
-
Java中的类只有单继承的关系,没有双继承的关系(相当于一个父类可以有多个子类,但是多个子类只能以有一个父类)。
1.this和super关键字
- super注意点:
- super 调用父类的构造方法,必须在构造方法的第一个。
- super 必须只能出现在子类的方法或者构造方法中。
- super 和 this 不能同时调用构造方法。
- super和this的区别:
- 代表的对象不同:
- this:本身调用者这个对象。
- super:代表父类对象的应用。
- 前提
- this:没有继承也可以使用。
- super: 只能在继承提哦见才可以使用构造方法。
- 构造方法
- this():本类的构造!
- super():父类的构造!
- 代表的对象不同:
/**
* @author yxf
*/
//Person人:父类
public class Person {
protected String name = "谢雪";
public Person(){
System.out.println("Person 无参构造被执行了");
}
//private 私有的东西无法被继承
public void print(){
System.out.println("Person 父类");
}
}
/**
* @author yxf
*/
//Student:子类,继承了父类Person
//子类也可以拥有属于自己的方法
public class Student extends Person{
public String name = "谢可寅";
public void print(){
System.out.println("Student 子类");
}
public Student(){
//隐藏代码,调用了父类的无参构造方法
//super(); //调用父类的构造器,必须在子类的第一行
System.out.println("Student 无参构造被执行了");
}
public void test1(){
print();
this.print();
super.print();
}
public void test(String name){
System.out.println(name+" = 传递的参数"); //输出shaking
System.out.println(this.name+" = 当前类"); //输出谢可寅
System.out.println(super.name+" = 父类的"); //输出谢雪
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.test("shaking");
student.test1();
}
}
2.方法重写
- 重写(Override):需要有继承关系,子类重写父类的方法!
1. 方法名必须相同。
2. 参数列表:列表必须相同。
3. 修饰符:范围可以扩大但不能缩小; public>protected>default>private。
4. 抛出的异常:范围,可以被缩小,但不能扩大;ClassNotFoundException --> Exception(大)。
总结:重写就是子类的方法,和父类必须要一致:方法体不同
/**
* @author yxf
*/
//父类
//重写都是方法的重写,和属性无关
public class B {
public void test(){
System.out.println("B-->test()");
}
}
/**
* @author yxf
*/
//子类
public class A extends B{
public void test(){
System.out.println("A-->test()");
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
//静态方法和非静态方法区别很大!!!
//静态方法:方法的调用只和左边定义的数据类型有关
public static void main(String[] args) {
A a = new A();
a.test(); //输出:A-->test()
//父类的引用指向了子类
B b = new A();
b.test(); //输出:A-->test(),子类重写了父类的方法);如果是静态方法则输出的是 B-->test(),方法没有被重写
}
}
- 为什么需要重写:
1. 父类的功能,子类不一定需要,或者不一定满足!
3.什么是多态
-
动态编译即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
-
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多(父类,you关系的类)。
-
多态存在的条件:
1. 有继承关系。
2. 子类重写父类方法。
3. 父类引用指向子类对象。 -
多态注意事项:
1. 多态是方法的多态,属性没有多态。
2. 父类和子类,有联系。 类型转换异常!ClassCastException:类型转换异常。
3. 存在条件:继承关系,方法需要重写,父类引用指向子类对象! Father f1 = new Son();
不能被重写:
1. static 方法,属于类,它不属于实例。
2. final 常量
3. private 方法
/**
* @author yxf
*/
//Person人:父类
public class Person {
public void fat(){
System.out.println("fat 父类");
}
}
/**
* @author yxf
*/
//Student:子类,继承了父类Person
//子类也可以拥有属于自己的方法
public class Student extends Person{
public void fat(){
System.out.println("子类重写了父类的fat方法");
}
public void son(){
System.out.println("son 子类独有的方法");
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student();
//new SPerson();
//可以指向的引用类型就不确定类
//Student 子类:能调用的方法都是自己的或者继承父类的!
Student s1 = new Student();
//Person 父类:可以指向子类,但父类不能调用子类独有的方法
Person s2 = new Student();
Object s3 = new Student();
s1.son();
s1.fat();
//对象能执行那些方法,主要看对象左边的类型,和邮编关系不大!
//s2.son();
//((Student)s2).son(); //强制转换,把Person类型转换成了Student
s2.fat(); //子类重写了父类的方法,执行子类的方法
}
}
- instanceof (类型转换) 引用类型,判断一个对象是什么类型。
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
//Object > String
//Object > Person > Teacher
//Object > Person > Student
Object obj = new Student();
System.out.println(obj instanceof Student); //true
System.out.println(obj instanceof Person); //true
System.out.println(obj instanceof Object); //true
System.out.println(obj instanceof String); //false
System.out.println(obj instanceof Teacher); //false
System.out.println("=====================");
Person per = new Student();
System.out.println(per instanceof Student); //true
System.out.println(per instanceof Person); //true
System.out.println(per instanceof Object); //true
//System.out.println(per instanceof String); //没有关联,编译就会报错
System.out.println(per instanceof Teacher); //false
System.out.println("=====================");
Student stu = new Student();
System.out.println(stu instanceof Student); //true
System.out.println(stu instanceof Person); //true
System.out.println(stu instanceof Object); //true
//System.out.println(stu instanceof String); //没有关联,编译就会报错
//System.out.println(stu instanceof Teacher); //没有关联,编译就会报错
}
}
/**
* @author yxf
*/
//Student:子类,继承了父类Person
//子类也可以拥有属于自己的方法
public class Student extends Person{
public void son(){
System.out.println("son 子类独有的方法");
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
//类型之间的转化:父 子
//高 低
Person obj = new Student();
//将Person这个对象强转换为Student类型,我们就可以使用Student类型里面的方法类!
((Student)obj).son(); //Student stu = (Student) new Person();
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
//类型之间的转化:父 子
//高 低
Person obj = new Student();
//子类转换为父类,可能会丢失自己独有的一些方法!
Student student = new Student();
student.son();
//将Person这个对象强转换为Student类型,我们就可以使用Student类型里面的方法类!
((Student)obj).son(); //Student stu = (Student) new Person();
}
}
- 多态总结:
1. 父类引用指向子类的对象。
2. 把子类转换为父类。向上转型。
3. 把父类转换为子类,向下转型(强制转换)。
4. 方便方法的调用,减少重复的代码。
4.static关键字
-
static静态变量在类中是共享的。
-
非静态方法可以访问本类中的所有静态方法。
-
静态方法可以调用本类中所有的静态方法。
原因:因为静态的方法是和mian方法一起加载出来的,加载之前还没有普通的方法,所以就无法调用。
/**
* @author yxf
*/
public class Student {
private static String name = "shaking"; //静态变量
public double score = 100; //非静态变量
public void run(){
System.out.println("run");
}
public static void go(){
//this.run(); //静态方法不能调用非静态方法
System.out.println("go");
}
public static void main(String[] args) {
Student student = new Student();
//没有用static修饰符的不可以直接调用,需要用new对象来调用
System.out.println(student.score);
student.run();
//用static修饰的可以直接调用
System.out.println(name);
go();
}
}
-
静态代码块(最早的执行);静态代码块只在一开始执行一次并且后面将不再执行。
-
匿名代码块在对象一创建的时候,就先走匿名代码块,然后再走构造器;作用:赋初始值。
-
构造器最后执行。
/**
* @author yxf
*/
public class Person {
public static void main(String[] args) {
Person person = new Person();
System.out.println("============是分割线呀============");
Person person1 = new Person();
}
// 2.第二执行,可以用来赋初始值
{
System.out.println("匿名代码块");
}
// 1.最先执行,只执行一次
static {
System.out.println("静态代码块");
}
// 3.最后执行
public Person(){
System.out.println("构造方法");
}
}
//输出的结果
/*
静态代码块
匿名代码块
构造方法
============是分割线呀============
匿名代码块
构造方法
*/
5.抽象类
-
抽象类定义;在普通类的结构里面增加抽象方法的组成部分。
-
抽象方法定义:是指没有方法体的方法。
-
关键字为:abstract。
-
注意:
1. 不能new这个抽象类,只能靠它的子类进行实现。2. 抽象类中可以写普通的方法。 3. 抽象方法必须在抽象类中。
/**
* @author yxf
*/
//abstract 抽象类: 类 :extends 需要继承 :类是单继承(接口可以多继承)
public abstract class Action {
//约束,有人帮我们实现
//abstract 抽象方法,只有方法名字,没有方法的实现!
public abstract void doSomething();
//1. 不能new这个抽象类,只能靠子类去实现它:约束!
//2. 抽象类中可以写普通的方法。
//3. 抽象方法必须在抽象类中。
//抽象的抽象:约束
public void hello(){
}
}
/**
* @author yxf
*/
//抽象类的所有方法,继承了它的子类,都必须要实现它的方法,除非子类也是个abstract类
public class A extends Action{
@Override
public void doSomething() {
}
}
6.接口的定义与实现
- 普通类:只有具体实现。
- 抽象类:具体实现和规范(抽象方法)都有!
- 接口:只有规范!自己无法写方法~专业的约束!约束和实现分离!面向接编程~
接口的定义:简单来说为某种特征的约定。
关键字:interface。
-
类可以实现接口 implements。
-
实现了接口的类,就需要重写接口中的方法。
-
利用接口实现多继承,但是与继承关系无关。
/**
* @author yxf
*/
public interface TimeService {
void time();
}
/**
* @author yxf
*/
//interface 定义的关键字.接口都需要有实现类
public interface UserService {
//接口中的所有定义的方法其实都是抽象的 public abstract
int insertUser();
int deleteUser(int id);
void queryUser();
}
/**
* @author yxf
*/
//抽象类: extends
//类 可以实现接口 implements 接口
//实现类接口的类,就需要重写接口中的方法~
//多继承~ 利用接口实现多继承~
public class UserServiceImpl implements UserService,TimeService{
@Override
public int insertUser() {
return 0;
}
@Override
public int deleteUser(int id) {
return 0;
}
@Override
public void queryUser() {
}
@Override
public void time() {
}
}
- 接口的作用:
1. 约束。
2. 定义一些方法。让不同的人实现功能。
3. 接口不能被实例化,接口中没有构造方法。
4. implements可以实现多个接口。
5. 必须要重写接口中的方法。
7.内部类
- 内部类就是在一个类的内部再定义一个类,比如A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。
- 成员内部类
定义:成员内部类是最普通的一种内部类,成员内部类可以访问外部类所有的属性和方法。但是外部类要访问成员内部类的属性和方法,必须要先实例化成员内部类。
/**
* @author yxf
*/
public class Outer {
private int id = 10;
private void out(){
System.out.println("这是外部类的方法");
}
public class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
//可以获得外部类的私有属性和方法~
public void getOuter(){
System.out.println(id);
out();
}
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
//通过这个外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.in();
inner.getOuter(); //获取外部类的私有属性和方法
}
}
- 静态内部类
定义:静态内部类就是在成员内部类多加了一个 static 关键字。静态内部类只能访问外部类的静态成员变量和方法(包括私有静态)
/**
* @author yxf
*/
public class Outer {
private int id = 10;
public void out(){
System.out.println("这是外部类的方法");
Inner.in();
}
public static class Inner{
public static void in(){
System.out.println("这是内部类的方法");
}
}
}
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
outer.out();
}
}
- 局部内部类
定义:局部内部类就是定义在代码块内的一个内部类。
局部内部类的作用范围仅仅就在它所在的代码块里。局部内部类不能被public ,protected,private以及static修饰,但是可以被final修饰。
//局部内部类
public void method(){
class Inner{
}
}
- 匿名内部类
定义:顾名思义就是没有名字的类。
/**
* @author yxf
*/
//一个项目只能有一个main方法
public class Application {
public static void main(String[] args) {
//匿名内部类:没有名字初始化类,不用将实例保存到变量中
new Apple().eat();
new UserService() {
@Override
public void hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println(1);
}
}
interface UserService{
void hello();
}
七、异常
定义:在程序运行过程中出现的错误,称为异常。异常就是程序运行过程中出现了不正常现象导致程序的中断。在Java中,把各种异常现象进行了抽象形成了异常类。
简单分类
- 要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:
- 检查性异常:检查时异常最具有代表性的就是用户错误或者是问题引起的异常,这种异常是我们程序员无法进行预测的。例如我们要打开一个文件时文件不见了,这些异常都是在编译时不能被简单的忽略的。
- 运行时异常:运行时异常是可能被程序员避免的异常,与检查时异常相反,运行时异常可以在编译时被忽略。
- 错误:错误不是异常,而是不被程序员控制的问题,错误在代码中通常被忽略。例如当栈溢出时,错误就产生了,并且在程序编译的时候也无法被找到。
1.异常处理机制
- 跑出异常
- 捕获异常
- 异常处理五个关键字
try、catch、finally、throw、throws
/**
* @author yxf
*/
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
try { //try 监控区域
System.out.println(a/b);
}catch (ArithmeticException ae){ //catch(想要捕获的异常类型) 捕获异常
System.out.println("程序出现异常,变量b不能为零");
}finally { //处理善后工作,无论是否有异常都会执行
System.out.println("finally");
}
}
}
注意:
- 程序的最后可以不要finally 。IO流以及资源需要关闭通常放在finally里面。
- 捕获异常可以catch多个,但是要把作用域最小的放在上面。
- 快捷方式:选中要捕获异常的代码 ctrl+t选择异常类即可。
/**
* @author yxf
*/
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
//如果要捕获多个异常,从小到大!
try { //try 监控区域
System.out.println(a/b);
}catch (Error e){ //catch(想要捕获的异常类型) 捕获异常
System.out.println("Error");
}catch (Exception e){
System.out.println("Exception");
}catch (Throwable t){
System.out.println("Throwable");
} finally { //finally 处理善后工作,无论是否有异常都会执行
System.out.println("finally");
}
}
public void a(){
b();
}
public void b(){
a();
}
}
- 我们也可以用throw来主动抛出异常。
/**
* @author yxf
*/
public class Test1 {
/**
* @Author代码贩子、 --南京邮电大学
*/
public static void main(String[] args) {
int a = 1;
int b = 0;
try {
new Demo01().text(1,0);
}catch (ArithmeticException e){
e.printStackTrace();
}
}
//假如这个方法中,处理不了这个异常,方法上抛出异常,在调用闪光也要进行捕获
public void text(int a, int b) throws ArithmeticException{
if (b == 0) {//主动抛出异常 throw 一般用在方法中
throw new ArithmeticException();
}
System.out.println(a/b);
}
}
- 自定义异常
- 定义:使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常,用户自定义异常类,只需要继承Exception类即可。
- 在程序中使用自定义异常类,大体可以分为以下步骤。
- 创建自定义常类。
- 在方法中通过throw关键字抛出异常。
- 如果在当前抛出异常的方法中处理异常,可以使用try——catch语句来捕获异常并处理,否则在方法的声明处通过throws关键字指明要抛出给方法调用的异常,继续下一步操作。
- 在出现异常方法的调用者中捕获并处理异常。
/**
* @author yxf
*/
public class Text2 {
static void Test(int a) throws Demo1 {
if(a>10){
throw new Demo1(a);//抛出
}else{
System.out.println("传递的参数为:"+a);
}
}
public static void main(String[] args) {
try {
Test(1);
}catch (Demo1 e){
System.out.println("Demo1"+e);
}
}
}
//继承Except异常类
public class Demo1 extends Exception{
/**
* @Author代码贩子、 --南京邮电大学
*/
//传递数字
private int detial;
public Demo1(int a) {
this.detial = a;
}
//异常的打印信息
@Override
public String toString() {
return "Demo1{" +
"detial=" + detial +
'}';
}
}
总结:
- 处理运行时异常时,采用逻辑法合理规避同时辅助try——catch处理。
- 在多重catch快后面,可以加一个catch(Exception)来处理可能会被遗漏的异常。
- 对于不确定的代码,也可以加上try——catch,处理潜在的异常。
- 尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出。
- 具体如何处理异常,要根据不同的业务需求和异常类的类型去决定。
- 尽量添加finally语句块去释放占用的资源。