javaSE学习随记
java基础
注释
-
有单行注释用//表示;
-
多行注释用/* */来表示;
-
文档注释用/**回车即可展示
注释并不会被编译,不会在运行的时候参与运行,只起到解释的作用,方便读者观看。
标识符和关键字
标识符的定义要求:
- 开头是字母或者是下划线或者是美元符号开头;
- 首字母后面也是字母下划线等字符组合;
- 不能用关键字作为标识符。
数据类型
java数据类型分为两类:基本类型和引用类型。
- 基本类型又分为
-
整数型(byte, short, int, long) , long类型定义的时候需要在定义的数值结尾加L;
-
浮点型(float, double) , float定义的浮点数在结尾添加f;
-
Boolean型,boolean型的值只能是true和false(不支持数值类型的转换)
引用类型分为
-
类
-
接口(面向对象)
-
数组
(例如:String定义的数值类型就是引用类型,)
类型转换以及整数拓展
1.计算机进制分为二进制0b,十进制,八进制0(写在开头),十六进制0x
2.在银行业务中尽量避免完全使用浮点数来比较,用BigDecimal数学工具类。
转义字符 \t 表示制表符相当于一个tab;
转义字符\n表示换行符,会使输出内容在标记位置换行。
3.java是强类型语言,在运算的时候需要用到类型转换:
低-------------------------------------------------------------------------->高()
byte,short,char——> int——> ——>float——>double
在运算过程中不同的数据类型先转化为同一个数据类型再进行比较运算较为妥当;
a.低等级到高等级的不需要强制转换,可以直接转换(自动转换);
b.高等级到低等级的需要强制转换:(转换类型)变量名(注:需要考虑到溢出的结果)
c.int类型不能转换为String类型,会报错。
变量
-
变量的定义:数据类型 变量名;
例:
-
变量有三种作用域:类变量,局部变量,实例变量。
局部变量是在一个方法中的变量,生命周期是从方法的开始到方法的结束(必须声明初始值)
实例变量在一个对象里面,属于是对象的属性,通过对象来调用这个变量;(可以不用初始值,所有变量都是默认值0或null)
类变量(静态变量)用static开头,我认为相当于全局变量,方便调用。
static int i = 10; // 全局变量,都可以调用。
-
拓展:常量用final开头来定义一个变量,常量标识符一般用大写字符。(final和static都属于修饰符,不分前后顺序写)
final double PI = 3.14; //定义一个常量 static final double A = 2.1; //定义的是一个类变量
运算符
-
算数运算符:+ ,-,*,/,%(取余),++,--
-
赋值运算符:=
-
关系运算符:< , > , == , <= , >= , != instanceof (输出结果是true或者是false)
-
逻辑运算符&&,||,!(与或非)
-
条件运算符 ?:(偷懒用的)
int score = 59;System.out.println(score>=60?"及格":"不及格"); //判断语句输出的是不及格
-
位运算符 | ,&, ^ , ~ (与二进制有关,两个二进制数进行与或非的操作^表示的是异或相同为0,不同为1)
幂运算表示的方式(使用一些工具类来表示)
位运算还包括<<表示左移,在二进制中进行左移,>>表示的是右移(效率高)
运算符的优先级
包机制和javaDoc
包的创建是将网址www.baidu.com反过来,也就是com.baidu.www
包可以被调用,避免调用包的名字与某个函数名字相同。
javaDoc代码
/**
* @author 作者名
* @version 版本号
* @since 知名最早使用的jdk版本
* @param 参数名
* @return 返回值
* @throws 异常抛出的情况
*/
流程控制
用户交互
用Scanner获取用户的输入:
与Scanner输入时字符串相关的方法:
- hasNext() / hasNextLine() 用来判断是否有数据输入; // 默认就是true;
- next() / nextLine() 是用来获取用户输入的字符串 但是next()输入的字符串有空格时候会忽略空格后面的内容,nextLine不会,所以说我感觉还是用nextLine来写比较方便;
- 类似的I/O输入输出的设备都需要在最后关闭;
Scanner相关类似使用
在进行定义整数时
Scanner sc = new Scanner(System.in);
int i = sc.nextInt(); //接收的是整数型
float f = sc.nextFloat(); //接收的是浮点型
同理hasNextInt()判断输入的是不是整数;
hasNextFloat()判断输入的是不是浮点数。
顺序结构
java最基本的结构就是顺序结构,按照顺序一句一句执行;顺序结构就是最简单的算法结构。
选择结构
选择结构分为:
-
if选择结构
if(布尔表达式1){}else if(布尔表达式2){}else if(布尔表达式3){}else{}
-
switch选择结构
支持byte,short,int,char类型,从jdk7开始支持String类型的,字符的本质就是数字。
java----->class----->(反编译)java
switch (expression){case value1://执行语句break;case value2://执行语句break;......default: //其余情况下执行的语句//执行语句 }
这个代码还是重大失误了,因为io设备最后必须要进行关闭,在代码后面添加一个sc.close();即可。
循环结构
-
while循环
while(布尔表达式){//写进循环内容 }
例子:
-
do...while循环
do{//写进循环语句 }while(布尔表达式)//相较于while相同条件比while多循环一次。至少循环一次。
// 进行1~100以内的和
-
for循环(最重要)
//初始化 //判断条件 //迭代 for(int i = 0; i <= 99; i++){//循环语句; }
奇数和 oddSum 偶数和 evenSum;
例子2:输出1000以内可以被5整除的数,并且每行输出三个
其中print和println的使用需要注意,println输出会换行,print输出不会换行。
例子3:输出一个九九乘法表
注意:for循环两层的话外层循环一次,内层循环完成完整的一轮!!!
for循环加强
-
遍历数组和集合,两种方法都可以进行遍历哈哈。
break与continue
break:
break可以直接终止循环,直接退出循环
例子1:在输出到30的时候直接终止循环因为break的原因。搭配if条件判断出奇制胜。
语言表述有误,应该是跳出循环,不会终止程序。
continue:
continue用于循环中用于终止某次循环过程,下一次循环还是要继续。
例子1:
break在任何循环主体中直接跳出整个循环结构,但是continue只是忽略本次循环继续下一次的循环工作
拓展
goto关键字,通过设置一个标记,可以利用continue直接跳过去,实在是高!
测试:打印三角形
java方法
- 方法包含在类或者是对象中
- 方法是语句的集合
- 在程序中被调用,在其他位置被调用
方法的定义以及调用
- 方法定义并调用
该图中是两个方法,一个是main方法,另一个是定义的加法。
方法分为静态方法和非静态方法,用static修饰的方法是静态方法,没有static修饰的方法是非静态方法;
-
定义格式
public, static是修饰符,学过的修饰符还有final(定义一个默认值);int 是返回值的类型,用return 来返回返回值,如果没有返回值可以用void表示,可以直接使用;add表示的是方法名;括号内表示写入的参数(形参);方法里的内容是方法体,return 后加返回值类型。
//修饰符 返回值类型 方法名 在方法中定义这个参数是形参;实参是在调用函数时所传入的参数。 public static void method(参数类型 参数名){方法体return 返回值; //方法有返回值类型的时候一定要有return来表示。 }
-
return 可以直接结束一个方法;如果方法有返回值的时候,方法的调用通常会被当作一个值。同理如果方法返回值是void(表示返回值为空)那么就是调用一条语句,就是直接输出方法里的输出。
方法重载
- 方法重载的条件需要方法名字相同,传入的参数数量和类型可以不一样(如果两个方法名字一样被调用时,根据输出的数据类型选择调用的方法)
-
返回值和修饰符可以不同也可以相同。(返回值不能作为方法重载的依据:方法的返回类型)
仅仅是返回值不同不足以构成方法重载,会出现错误,需要对传入的参数列表进行更改。
重要!!!
java中的方法中参数的传入是值传递,搜到的对象是引用传递(本质上还是值传递)
可变参数
好像也是不定项参数,就是在进行方法定义的时候不知道传进去多少个参数,那么就在数据类型后面添加一个省略号(表示输入的参数个数不确定),感觉跟一个数组一样。
- 在定义可变参数的时候,可变参数类型必须要放在传递参数的最后一个,而且只能有一个;
递归
递归就是自己调用自己,类似于 f(n) = 1 ,n = 1时;f(n) = nf(n-1),n>1时。
在程序中占用的空间较大尽量不递归。
例子:求阶乘(利用递归就可以进行自己调用自己完成)
递归结构有两部分组成:
- 递归头:上述例子里n==1的情况应该是递归头,如果没有头会陷入死循环;
- 递归体:n*f(n-1)表示的是递归体。
测试
输出一个具有加减乘除功能的计算器
package method;import java.util.Scanner;public class Test {public static void main(String[] args) {Scanner sc = new Scanner(System.in);for (int i = 0; i < 3; i++) {System.out.print("你还有" + (3-i) + "次机会");System.out.println("请选择你的计算方式:");int a = sc.nextInt();switch (a) {case 1:System.out.println("请输入两个整数进行加法运算");int sum = add(sc.nextInt(), sc.nextInt());System.out.println(sum);break;case 2:System.out.println("请输入两个整数进行减法运算");int sub = sub(sc.nextInt(),sc.nextInt());System.out.println(sub);break;case 3:System.out.println("请输入两个整数进行乘法运算");int mul = mul(sc.nextInt(),sc.nextInt());System.out.println(mul);break;case 4:System.out.println("请输入两个整数进行除法运算");int div = div(sc.nextInt(),sc.nextInt());System.out.println(div);break;default:System.out.println("请重新输入");continue;}if (a == 1 || a == 2 || a == 3 || a == 4){System.out.println("计算结束");break;}}}//加法public static int add(int a,int b){return a+b;}//减法public static int sub(int a,int b){return a-b;}//乘法public static int mul(int a,int b){return a*b;}//除法public static int div(int a,int b){return a/b;}}
数组
数组的概述
- 数组是相同数据类型的有序集合!!有序!!
- 按照先后顺序排列组合而成
- 每个数据都是数组元素,可以通过下标来访问他们(下标是从0开始的)
对数组进行赋值并遍历数组,可以看到数组第一个元素的下标是0,并且可以通过for循环来对数组进行赋值和遍历。
数组的声明与创建
数组的声明:(这个先定义了一个数组,再进行使用)
int[] arr; //声明定义一个数组,没有开辟空间;
arr = new int[5]; //开辟了5个空间。
int[] arr = new int[5]; //声明定义一个数组,并且开辟(创建)五个空间。
//arr.length表示的是数组的长度,就是定义的5。
注意!数组开辟空间后不能更改数组的长度。
//计算数组元素的总和;int sum = 0;int[] arr3 = new int[5]; //定义一个数组并开辟5个空间。for (int i = 0; i < arr3.length; i++) { //arr3.length表示的是数组的长度arr3[i] = i;sum+=arr3[i];}System.out.println("总和是:"+sum);
java内存分析:
- 堆里面存放new出来的对象和数组
- 栈里面存放的是基本变量类型
注:当定义一个数组的时候数组会在栈内存中,开辟一个数组元素的时候会在堆中占用一个空间。数组中int[]类型元素的默认值为0;
例如:当一个数组中有五个数据,访问的下标是5,那么会发生下标越界的报错。
这个图片是表示下标越界的报错!!!
数组的初始化方式:
1.静态初始化:创建+赋值。
int[] arrays = {1,2,3}; //静态初始化方式,直接定义了数组里面的内容,不可改变;
2.动态初始化
int[] arrays = new int[3]; //动态初始化方式,只是定义一下数组里面的元素数量。
//数组有默认值,int类型都是0,String类型都是null。
数组是引用类型的。
数组的基本特点:
-
数组的长度都是确定的,一旦被定义都是不能再改变的;
-
数组中的数据类型都是相同的,不能出现混合类型,并且是一个有序集合;
-
数组中的元素可以是基本类型,也可以是引用类型;
-
new出来的对象是在堆中的,对象类型是保存在堆中的,数组对象和原始类型都是保存在堆中。
-
数组变量是引用类型。
数组的使用
- for-each循环
//遍历数组中的值,但是取不到下标int[] arrays = {1,2,3,4,5};for (int arr: arrays){System.out.println(arr);}
- 反转数组
int[] arrays = {1,2,3,4,5};int[] reverse = reverse(arrays);for(int r: reverse){System.out.println(r); //输出的是5,4,3,2,1}}//反转数组public static int[] reverse(int[] arrays){int[] result = new int[arrays.length];//如果填的是i小于arrays.length-1那么会遍历不到最后一个元素,会出现默认值for (int i = 0,j = arrays.length -1 ; i <= arrays.length-1; i++,j--) {result[i] = arrays[j];}return result;}
在这个反转数组的例子中,数组作为可以作为形式参数写进方法中,也可以作为返回值类型return出去!!!
二维数组
//二维数组的定义
int a[][] = new int[2][5];
//这个数组表示的类似于一个两列五行的表格,
定义的这个二维数组中长度分别是arr.length; //2arr[i].length; //5
多维数组都是差不多的。
遍历一下二维数组
直接输出一个数组输出的是一个地址,并不是这个数组的里面的内容。
冒泡排序
- 冒泡排序就是数组中每次两个数进行比较 arr[i] 与 arr[i+1] 进行比较,一共比较 arr.length-1次。
- 每一次外层循环都会筛选出一个最大值或者是最小值,内层循环中比较都会少进行一次。
- 时间复杂度是O(n2)
Arrays的工具类
//Arrays.sort(int[] a); //值进行排序不输出;
//Arrays.toString(int[] a); //放在sout中可以直接输出一个完整的数组。int[] arr = {1,6,3,8,7,3,14};
Arrays.sort(arr);//直接对数组进行排序,输出的结果也是排完序的样子。
System.out.println(Arrays.toString(arr)); //可以直接输出一个完整的数组[1, 3, 3, 6, 7, 8, 14]
System.out.println(Arrays.equals(a, arr)); //比较两个数组是否相同
面向对象
-
java的核心思想就是面向对象编程(oop)。
-
面向对象三大特性:封装,继承,多态。
-
以类的方式组织代码,以对象的方式封装数据。
-
抽象(真抽象)
-
代码运行角度来看是先有类再有对象
注:前面的学习都是面向过程!!
面向对象前的巩固
属性加方法就是一个类,大概是这样的吧,简单的理解。
public class 类名{1.静态的属性2.动态的方法:构造器实际上就是方法
}
- 方法中静态方法是有static修饰的,非静态方法没有static修饰。非静态方法不能被直接调用,只能将类实例化然后调用。new出来一个对象就是将这个类实例化,可以轻松调用,有static调用可以直接通过类名调用。
static是和类一起加载的,当类出现的时候static已经出现了,非静态方法是类实例后才出现(new之后)
引用传递例子
student是引用变量名指向的是堆中的数据。
类与对象的创建
- 类是一种抽象的数据类型,顾名思义就是可以理解为 int,String.......多种数据类型,但是是你自己定义的
一个项目中只能有一个main方法;
定义的类包含了属性和一些可以被调用的方法(静态方法可以被直接调用,非静态方法需要new出来的实例调用!!!)
this.name指的是类中的属性, 赋值的name是调用时传进来的实参。
- 对象是类的具体事物
类中定义的非静态方法需要将类实例化之后才可以调用,简而言之就是用new出来的对象来调用方法。
对象真是一个神奇的东西,他是引用类型的。
假设有一个Student类Student s1 = new Student(); //s1就是引用类型的变量,它存放在栈中,类中它所包含的属性存放在堆中。
构造器
- 当类中什么都不写的时候会默认有一个无参数的方法,这个方法的名字必须跟定义的类名是相同的。
//无参数的方法定义
public 类名(){}
//1.默认的无参构造器会自动帮助数据初始化。2.使用new关键字定义本质上是在调用无参构造器
类名 a = new 类名(); //调用类中的无参构造器
- 当类中定义了一个有参构造器时候,无参构造器必须显示定义出来!!不然会报错!!(我在我电脑上试的时候不会报错,还可以运行)
无参构造器和有参构造器在我看来就像是方法重载一样,只是没有写方法的返回值一类的。
构造器的作用:
-
没有返回值,与类名相同
-
new实际上是在调用构造器,如果里面有内容的话也会进行输出等操作
-
初始化对象的值
-
如果定义了有参构造器时候,想使用无参构造器时候,必须将无参构造器写出来,但是不知道为什么我的idea只写有参构造器也行。
内存分析
类与对象
1.类是一个模板,对象是类的具体实例
public class 类名{String name;......
}//其它类中
类名 a = new 类名(); //创建一个对象,将类实例化,必须用new关键字
对象就是通过引用进行操作的,是从栈中一个地址找到堆中的。
-
对象的属性
对象的属性就是在另一个类中定义的一些String name;一些定义类型的很多,可以用 对象名.属性来对对象的具体信息进行编辑,方法也是这样调用的。
封装
简而言之就是将一个类中的属性私有化(private修饰),通过写get/set方法来对属性进行访问。
将Animals类中的name和age私有化(添加了private修饰),不能被直接调用。
私有化属性的使用方法:
通过调用get/set方法进行设值以及获取
总结:
用private私有化 ,用get/set方法进行设值和获取,再进行调用即可。
可以在封装中对数据进行合理化判断,如果不合格可以通过代码进行修改,提高代码的可维护性。
继承
简单地说就是父类和子类之间的关系,主要是针对类,用extends来表示关系。子类是父类的扩展。所有的类都是object类的子类。
// 动物类,同时也是狗类的父类
public class Animal{
}// 狗类,
public class dog extends Animal{
}
子类会继承父类的所有方法,但是私有化的方法不能被继承,封装后的属性不能直接继承,需要在父类中写get/set方法后子类继承,受保护类的可以继承(proteced修饰的)。
ctrl + H可以看到项目的父类子类的结构(可以看到所有的类都直接或者是间接的继承object类)
注:java中只有单继承没有多继承,一个儿子只能有一个爸爸,一个爸爸可以有多个儿子
super关键字
跟this有一拼,this代表当前的,通常指向的都是当前类中的属性;但是super是指向的是父类中的属性。
在继承中尽管是将子类实例化,实例化时调用无参构造器,子类的无参构造器中默认的有父类的无参构造器。而且先输出的是父类的,可以通过debug看运行顺序。是这样的!
super的注意点:
1.super是调用父类构造器,必须在构造方法的第一个(在子类构造器中),如果直接默认的话是在子类的无参构造器中的第一个,先执行 super();,调用父类
2.this 和super不能同时调用构造方法。
对比:
1.本身调用的对象不一样
this:调用的是自己本身
super:代表的是父类
2.this本身就可以使用;super只有在继承中才能用。
方法的重写
1.方法重写就是在继承的情况下,父类的方法不好用,或者不能满足自己的需求时候,子类可以重新写一个名字和参数列表都一样的方法对父类方法进行覆盖
2.对重写的方法用@override进行注解,私有方法(private)静态方法(被static修饰)不能被重写,不然会报错。以下就是static修饰的方法进行重写报错。
3.重写的方法返回值类型必须与重写的方法返回值类型一样或者更小。(子比父小即可)例子中也可以返回new A();尽量保持一直就行
在这个例子中父类只顾着玩手机,我觉得不妥,于是对他进行重写,对他进行覆盖,调用到的是子类的被重写过的方法,如果重写的方法不存在,则直接调用父类的方法!!
多态
分为:1. 对象多态; 2. 行为多态
People p = new Student(); //父类的引用指向子类的对象//以上属于对象多态的定义方式p.run();//属于是行为多态了
多态的前提:
- 有继承/实现关系
- 存在父类的引用指向子类的对象
- 存在方法重写
存在继承并且有方法重写,并且有父类的引用指向了子类,执行的是对象的方法
多态的成员访问特点:
People people = new Student();
1.方法的调用:编译看左边(在idea中写进去),运行看右边
2.成员变量的调用:都是看父类看左边。
图中p就是多态对象。
instanceof关键字
sout(a instanceof B); //a是定义的对象,B是一个类
主要判断a定义时候是父类引用的是子类的哪个对象,倘若B是引用子类的父类或者是同类,那便是输出true,不是就是false
类型转换
类型之间的转换:
1. 基本类型之间的转换:(内存)低 ===>高默认转换高 ===>低需要强制类型转换
2. 类型之间的转换:(父类子类之间的转换)
子类可以调用父类里面的方法,但是父类调用子类的方法需要转换成子类父类转化为子类(向下转型):需要强制类型转换子类转化为父类(向上转型)
以上是一个类型转换的小例子
抽象类
抽象类就是一个类用abstract修饰,定义如下
public abstract 类名{}
抽象类的特点:
-
不能被实例化(不能创建对象)必须由子类调用来实现。
-
抽象类中可以写抽象方法(用abstract修饰的方法)和非抽象方法,但是抽象方法必须在抽象类中
抽象方法:可以通过子类的重写再通过子类进行调用(规范体现)
非抽象方法:让子类继承
-
抽象类里面含有抽象方法时,他的子类必须重写所有的抽象方法!
-
抽象类的成员特点:
成员变量:变量和常量都可以
成员方法:可以有抽象方法也可以有非抽象方法
构造器:有构造器,但是需要通过子类来访问构造方法才能给抽象类的变量初始值化
抽象类不能被实例化例子:
抽象类中的抽象方法必须被子类重写才能罢休!
注意:抽象方法不能有方法体
接口
接口是用interface修饰的类,它里面的方法只能是抽象方法,比抽象类还抽象的类。
public interface 接口名{ //实现接口时候用implements来实现//只能写抽象方法!!//常量//没有构造器
}class A implements 接口名{//实现类需要重写父类的方法
}
- 接口不能实例化,不能创建对象
-
- 接口中必须写抽象方法(也可以有静态方法static修饰和默认方法default修饰jdk8可以满足)
- 接口中定义的成员变量都是常量,是默认的可以不写修饰词
- 接口中的抽象方法必须在实现类中全部重写!!或者说是这个实现类也是一个抽象类一个也不写。用implements关键字来对接口实现
- 接口中没有构造器
- 一个实现类可以实现多个接口,同时也可以直接继承父类。
StringBuilder
StringBuilder四个方法
- append(将数据直接追加到原本字符串的后面)直接对sb对象打印不会打印出地址,他已经经过处理了
- reverse(将字符串反转)
- length(获取字符串的长度)
4.toString(将数据类型换成String类型字符串)
在进行字符串比较的时候,将要比的字符串转换成String才行,用equals方法比较才行。
使用StringBuilder的场景:
- 字符串的拼接。(append)
- 字符串的反转(reverse)
随后补充吧。。