有一点java基础所以记笔记各有侧重,大家选择性食用就好
入门
hello world
java三大版本:JAVASE(标准版,桌面程序、控制台),JAVAME(嵌入式), JAVAEE(企业级,web端,服务器)
JDK:java development kit,除了java/javac/jar,包括JRE和JVM
JRE:java runtime environment,包含JVM,只需要运行环境可以安装JRE
JVM:java virtual machine,跨平台的核心
卸载安装
卸载jdk: 删除jdk安装目录、删除JAVA_HOME和path下相关的环境变量、cmd查看java -version
安装jdk8: oracle下载安装、配置JAVA_HOME和path的环境变量、cmd输入java -version
java运行机制
编写java程序:新建.java文件,javac编译生成class文件,java运行class文件(不需要.java)
**编译型:**源代码全部转换为可执行代码,执行速度快,操作系统常用
**解释型:**逐句解释,网页常用(对速度要求不高)
随着硬件发展,编译和解释界限逐渐模糊
java代码在JVM前先编译,到操作系统前再解释
基础语法
注释
单行:// 注释;多行:/*注释*/;
文档注释:javadoc,/**注释*/
标识符
关键字:java规定过的名字,不能用关键字再命名类、变量或者方法
String不是关键字,是一个类
标识符只能以字母、下划线或$开头,可包含字母、数字、_、$,大小写敏感,可使用中文
数据类型
强类型语言:变量必须先定义后使用,java/c++,安全性高但速度慢
弱类型语言:VB/JS
八大基本类型
定义long需要在数字后加上L,float在后面加上F
位(bit):计算机存储最小单位
字节(byte):数据处理的基本单位,1B=8bit
整数进制
二进制0b开头,八进制0开头,十六进制0x开头
浮点数问题
浮点数是有限且离散的,存在舍入误差,只是接近但不等于具体数值
最好避免浮点数进行比较,尤其是double和float的比较
银行业务中采用BigDecimal数学工具类
字符
字符本质还是数字,可以通过(int)进行强制类型转换
unicode编码,‘a’=97=‘\u0061’,‘A’=65,U0000-UFFFF共2^16
转义字符:\t, \n等
类型转换
byte,short,char–>int–>long–>float–>double
强制转换:高->低,容易出现内存溢出或精度问题
自动转换:低->高
注意:不能对bool进行转换
引用类型——类、接口、数组
变量
变量包括变量名、类型、作用域
作用域:
类变量:static定义,从属类
实例变量:方法外面,类里面,从属于对象,默认值为0/null/false
局部变量:方法里面,必须声明和初始化
常量
初始化后不再改变,final定义,一般使用大写字符和下划线
运算符
关系运算符:instanceof
条件运算符:? :(三元运算符)
自增自减:++,–(一元运算符)
ctrl+D 复制当前行到下一行
位运算
&、|、~、^、>>、<<、效率高
次幂运算怎么最快: 2<<3=16
<<表示*2,>>表示/2
字符串连接符
+两侧出现String,则为字符串,否则为加法运算
优先级
多用()
包机制
用于组织类,区别类名的命名空间(不同包可以有同名类,但互相import时会报错)
《阿里巴巴开发手册》
javaDoc
生成自己的API文档,@parameter 参数名
package com.lqr;
/** 类的注释
* @author lqr
* @version 1.0
* @since 20221115
*/
public class hello {
String name;
/**方法的注释
* @parameter none
* @return name
* @throws Exception
*/
public String getName() throws Exception{
return name;
}
}
终端打开文件夹,输入以下命令,生成的文件中index.html可以从浏览器打开
javadoc -encoding UTF-8 -charset UTF-8 xxx.java
流程控制
用户交互Scanner
next和nextLine
Scanner类获取用户输入,通过Scanner类的next()与nextLine()方法获取输入的字符串,
在读取前一般需要使hasNext()与hasNextLine()判断是否还有输入的数据
IO流为了避免占用资源,养成close习惯
Scanner scanner = new Scanner(System.in);
if(scanner.hasNextLine()){
String str = scanner.nextLine();//输入: 123 23
System.out.println(str); //输出: 123 23
}
if(scanner.hasNext()){
String str = scanner.next();//输入: 123 23
System.out.println(str); //输出:123(没有空格)
}
scanner.close();
next会自动去掉有效字符前的空格,有效字符后的空格作为结束,不能接受带有空格的字符串
nextLIine以回车结束,可以获得空白
scanner接收其他类型
hasNextInt(),hasNextFloat()等,
用while,则以非数字为结束符;用if,则以回车为结束符
Scanner scanner = new Scanner(System.in);
double sum = 0;
int n = 0;
//scanner 输入多个数字 以非数字结束 求总和、均值
while(scanner.hasNextDouble()){
double i = scanner.nextDouble();
sum += i;
n++;
}
System.out.println("sum: "+ sum);
System.out.println("avg: "+ sum/n);
scanner.close();//IO流为了避免占用资源,养成close习惯
顺序、选择、循环
switch
switch语句谨记case后加上break
IDEA项目结构中可以查看编译后的claa文件位置,用IDEA可以直接打开反编译后的class文件
javaSE7开始,switch支持String类型
switch(xxx){
case xxx:
...;
break;
case xxx:
...;
break;
for
print不换行,println输出完换行
IDEA for循环快捷:10.for——for(int i = 0; i < 10; ++i)
//打印九九乘法表
for(int i=1; i<10; ++i){
for(int j=1; j<=i; ++j){
System.out.print(j+"x"+i+"="+(i*j)+"\t");
}
System.out.println("");
}
增强for
int[] a = {1,2,3}
for(int x:a){
System.out.println(x);
}
break/continue/goto
java没有goto,但有带标签的break和continue
对Java来说唯一用到标签的地方是在循环语句之前
在循环之前设置标签的唯一理由是:希望在其中嵌套另一个循环,使得break和continue可以中断到存在标签的地方。
outer: for(int i = 101; i<150; ++i){
for(int j=2; j<i/2; j++){
if(i % j==0)
continue outer;//这里用break是一样的
}
System.out.println(i);
}
//打印五行三角形
for (int i = 0; i < 5; i++) {
for (int j = 5; j > i; j--) {
System.out.print(" ");//左上角空白
}
for (int j = 0; j <= i; j++) {
System.out.print("*");//左下角
}
for (int j = 0; j < i; j++) {
System.out.print("*");//右下角
}
System.out.println("");
}
//方法二
int n = 5;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n-i-1; j++) {
System.out.print(" ");//左上角空白
}
for(int j=1; j<=2*i+1; j++){
System.out.print("*");//每行*的数量为奇数
}
System.out.println("");
}
方法
定义
修饰符+返回类型+方法名+参数(形参/实参)+方法体
return即可以返回值,也可以终止方法
调用
- 静态方法调用:类名.方法名 直接调用
- 非静态方法:用new实例化类,用对象名.方法名调用
- 静态方法中无法调用非静态方法:静态方法与类一起加载的,非静态方法在类实例化后才能使用
值传递和引用传递
Java是值传递
public class test{
public void seta(int a){
a =10;
}
public static void main(String[] args) {
int a = 1;
System.out.println(a);//1
new Student().seta(a);
System.out.println(a);//1
}
}
对象是引用传递
public class student{
String name;
public void setName(String name){
this.name = name;
}
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.name);//null
student.setName("lqr");
System.out.println(student.name);//lqr
}
}
重载
**规则:**名字一样、参数列表不同(个数或类型或顺序)
public static int max(int a, int b){
return a>b?a:b;
}
public static int max(int a, int b, int c){
if(a>b){
return a>c?a:c;
}
else{
return b>c?b:c;
}
}
public static double max(double a, double b){
return a>b?a:b;
}
命令行传参
希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给main()函数实现
public class hello {
public static void main(String[] args) {
for(int i=0; i<args.length; i++){
System.out.println("args["+i+"]: "+args[i]);
}
}
}
要回退到src下才能运行class文件
可变参数
本质是数组
在方法声明中,在指定参数类型后加一个省略号(….),可以获得不定项的参数,但这些参数类型必须相同
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数
递归
递归头(什么时候调用结束)+递归体(什么时候调用)
边界条件+前阶段+返回阶段——Java的栈机制,递归调用次数太多容易栈溢出
public static int fun(int n){//递归求阶乘
if(n==1)//边界条件
return 1;
else
return n*fun(n-1);
}
数组
同类型数据的有序集合,按下标访问
数组元素可以是基本类型或引用类型(任何类型)
数组变量属于引用类型,可以看成对象,数组元素相当于成员变量
声明创建
java使用new创建数组,用来开辟空间,一经创建无法改变
int[] a;//声明,在栈里有a
int a[];//C/C++
a = new int[10];//创建,在堆里有a指向的十个int的空间
a[2] = 3;//赋值
a.length;//数组的length属性
静态初始化
直接在定义的时候赋值(初始化),同时确定了长度
int[] a = {1,2,3};
动态初始化
先创建,后赋值
int[] a = new int[2];
a[0] = 1;
a[1] = 2;
默认初始化
数组是引用类型,它的元素相当于类的实例变量,一经分配空间,每个元素也被按照实例变量同样的方式被隐式初始化
int[] a = new int[2];//此时a[0]和a[1]均为0
java内存
数组声明时在栈里有变量,指向创建时在堆里的空间
new出来的都在堆里
使用
public static int[] reverse(int[] n){//反转数组
int[] m = new int[n.length];
for (int i = 0, j = n.length-1; i < n.length; i++, j--) {
m[j] = n[i];//j从length-1开始
}
return m;
}
多维数组
int[][] a = new int[2][3];//两行三列数组
for(int i = 0; i < a.length; ++i){
for(int j = 0; j < a[i].length; ++j){//遍历二维数组
...
}
}
Arrays类
数组的工具类java.util.Arrays,Arrays类中的方法可以直接使用类名进行调用
int[] a = {1,3,23,44,112,452,12,34,23124};
Arrays.sort(a);//升序排序(无返回值,修改本身
Arrays.fill(a, 0);//用0赋值每个元素,无返回值,修改本身
Arrays.fill(a, 1, 3, 0);//用0赋值1和2下标的元素,无返回值,修改本身
System.out.println(Arrays.toString(a));//利用Arrays打印数组
冒泡排序
public static int[] sort(int[] a){
int temp;
boolean flag;
for (int i = 0; i < a.length; i++) {
flag = false;//尚未排序
for(int j = 0; j<a.length-1-i; j++){
if(a[j]>a[j+1]){//升序排序,降序只需把>改成<
temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
flag = true;//执行了排序操作
}
}
if(!flag)//这一轮没有执行排序操作,说明已经有序,提前跳出
return a;
}
return a;
}
稀疏数组
数组存在大量同值元素时,
- 记录数组几行几列,多少个不同值
- 不同值的元素位置和值记录在小规模数组中
public static int[][] array(int[][] a){//稀疏数组存储为小数组
int[][] arr;
int sum = 0;
for (int i = 0; i < a.length; i++) {//统计有效值
for (int i1 : a[i]) {
if(i1!=0)
sum++;
}
}
arr = new int[sum+1][3];//创建稀疏数组
arr[0][0] = a.length;
arr[0][1] = a[0].length;
arr[0][2] = sum;
sum = 1;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {//稀疏数组赋值
if(a[i][j]!=0){
arr[sum][0] = i;
arr[sum][1] = j;
arr[sum++][2] = a[i][j];
}
}
}
return arr;
}
public static int[][] array2(int[][] a){//小数组转换为稀疏数组
int[][] arr = new int[a[0][0]][a[0][1]];
for (int i = 1; i <= a[0][2]; i++) {//填充有效值
arr[a[i][0]][a[i][1]] = a[i][2];
}
return arr;
}
面向对象OOP
面向过程->面向对象(适合处理需要多人协作的问题)
面向对象编程的本质就是以类的方式组织代码,以对象的方式组织(封装)数据
从认识的角度是先有对象再有类,从代码的角度是先有类再有对象
一个项目应当只存在一个main方法入口
对象
创建
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
构造器(构造方法)
设置-项目结构-添加根目录-选择out文件夹添加,out中为class文件,会为类自动添加构造方法
**构造器的特点:**名字必须和类名相同;没有返回类型也不写void
**构造器作用:**初始化对象的值
注意:
- 使用new关键字实际上是在调用构造器
- 一旦定义了有参构造,就必须显式定义无参构造,否则报错
快捷键alt+insert生成构造器
三大特性
封装
高内聚:内部数据操作细节由自己完成,不允许外部干涉
低耦合:尽量暴露少量方法供外部使用
属性私有;get/set
private属性外部无法直接访问,对象也无法直接调用
作用:提高安全性,保护数据,隐藏代码细节,统一接口,提高可维护性
public class Student {
private String name;
private int age;
private boolean gender;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public boolean getGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public void setName(String name){
this.name = name;
}
private void setAge(int age) {
if(age>200 || age<0)
this.age = 0;
else
this.age = age;
}
}
继承extends
JAVA中类只有单继承,没有多继承
子类和父类是“is a”的关系,除了继承,java中类之间的关系还有组合、聚合等
子类继承父类,会拥有父类的全部方法(private除外)
快捷键ctrl+h,展示继承关系树
java中所有类默认继承Object类,getClass方法可以获得当前类
super
public class Person {
private String name;
private int age;
private boolean gender;
protected int money = 10_0000_0000;
}
public class Student extends Person{
private int money = 1000;
public void print(){
System.out.println(money);//1000
System.out.println(this.money);//1000
System.out.println(super.money);//10_0000_0000
}
public static void main(String[] args) {
Student lqr = new Student();
lqr.print();
}
}
this访问当前类,super访问父类
构造对象时,先调用父类构造器,再调用子类构造器
注意:
- 使用super()调用父类构造方法,必须在构造方法的第一句
- super只能出现在子类的方法中,表示父类对象的引用
- super和this不能同时调用构造方法,因为两个都必须在第一句
方法重写
注意:
- 方法名必须相同,参数列表必须相同(参数列表不同的叫重载)
- 修饰符权限范围可以扩大,不能缩小
- 抛出异常的范围可以缩小,不能扩大
- static/final/private方法不能重写
**静态方法:**父类的引用指向子类,方法的调用只和定义的类型有关(new的左边)
**非静态方法:**子类重写父类的方法后,只调用子类方法
快捷键alt+insert,override生成重写方法
多态
new方法新建对象,实际类型确定,但指向的引用类型不确定
子类能调用的方法包括继承的方法和自己的方法
父类的引用指向子类时,不能调用子类的方法,可以通过强制转换再调用
注意:
- 多态是方法的多态,和属性无关
- 有继承关系,有方法重写,父类引用指向子类对象时,才是多态
instanceof 引用类型转换
instanceof判断对象实际类型与类之间是否有继承关系
public class Student extends Person{
public static void main(String[] args) {
Object o = new Student();
System.out.println(o instanceof Student);//true
System.out.println(o instanceof Person);//true
System.out.println(o instanceof Teacher);//false
System.out.println(o instanceof String);//false
System.out.println("==========");
Person p = new Student();
System.out.println(p instanceof Student);//true
System.out.println(p instanceof Person);//true
System.out.println(p instanceof Teacher);//false
// System.out.println(p instanceof String);//报错
System.out.println("==========");
Student s = new Student();
System.out.println(s instanceof Student);//true
System.out.println(s instanceof Person);//true
// System.out.println(s instanceof Teacher);//报错
// System.out.println(s instanceof String);//报错
}
}
子类转换为父类可以直接转换,但可能会丢失方法
父类转子类需要强制转换,转换后才能调用子类的方法
static
静态属性
既可以用类来调用,也可以用对象来调用,若在类里面,还可以直接调用
静态属性是属于类的,建议使用类名.来调用
静态方法
既可以用类来调用,也可以用对象来调用,若在类里面,还可以直接调用
静态代码块只在第一次创建对象时执行一次;
匿名代码块中可以用来赋初始值;
import static java.lang.Math.random;//静态导入包,可以直接调用
public static void main(String[] args) {
double r = random();
}
被final修饰的类不能再被继承
抽象类
abstract修饰类名,abstract修饰方法名时,没有方法体
public abstract class Person {
public abstract void say();
}
注意:
- 抽象类的子类都必须实现它的抽象方法,除非子类也是抽象类
- 抽象类不能new一个对象,只能通过子类来实现
- 抽象类中可以有非抽象方法,抽象方法只能存在于抽象类中
接口
类是单继承,但接口是多继承
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有
接口:只有规范!!自己无法写方法体,约束和实现分离,面向接口编程
接口中的所有方法都不能有方法体,都是public abstract,所有属性都是public static final;
接口通过interface定义,实现类通过implements实现;
一个类可以实现多个接口——多继承;
实现接口必须重写接口中的方法;
接口不能被实例化,没有构造方法
内部类
public class hello {
private int id=10;
public void out(){
System.out.println("外部类方法");
}
class Inner{
public void in(){
System.out.println("内部方法");
}
public int getId(){
return id;//内部类可以获得外部类的私有属性
}
}
}
public abstract class Person {
public static void main(String[] args) {
hello hello = new hello();
hello.Inner inner = hello.new Inner();//通过外部类实例化内部类
inner.in();//内部方法
}
}
不能通过外部类实例化静态的内部类
一个java文件中只能有一个public class,但可以有多个class
public class hello {
private int id;
public void out(){
class Inner{//局部内部类
public void in(){
System.out.println("内部方法");
}
}
System.out.println("外部类方法");
}
public static void main(String[] args) {
}
}
匿名初始化类,new XXX().XX();,不用把实例保存到变量中
异常
检查性异常:用户错误引起,程序员无法预见(例如,文件不存在)
运行时异常:在编译时可以被忽略,但程序员可以避免
错误:错误不是异常,是脱离程序员控制的问题,在代码中经常被忽略,例如栈溢出
java的异常处理机制
error由java虚拟机生成并抛出,与程序员无关,出现时JVM会终止线程
exception程序中可以捕获处理
处理异常
int a = 1;
intb = 0;
try {
System.out.println(a/b);
}catch (ArithmeticException e){
System.out.println("除0了!!!");
}finally {
System.out.println("无论是否异常都会执行");
}
catch可以叠加,捕获多个异常,但最大的异常应该在最下面,否则会执行不到
快捷键ctrl+alt+t,自动对选中的代码生成try catch finally语句块
抛出异常
主动抛出异常:throw关键字,一般在方法中使用
方法抛出异常:throws关键字,在调用时可以捕获
自定义异常
- 创建异常类,继承Exception类
- 在方法中通过throw抛出异常
- 如果在当前方法抛出异常并处理,要用try-catch捕获处理
- 如果在方法声明时throws异常,在方法调用时try-catch捕获处理
public void a(int aa){//方法定义时处理异常
if(aa>10){
try {
throw new MyException(aa);
} catch (MyException e) {
throw new RuntimeException(e);
}
}
}
public void a(int aa) throws MyException {//方法调用时处理异常
if(aa>10){
throw new MyException(aa);
}
}
//一个例子
public class MyException extends Exception{
private int a;
public MyException(int a) {
this.a = a;
}
@Override
public String toString() {//打印信息
return "MyException{"+"a="+a+"}";
}
}
public static void main(String[] args) {
try {
hello.test(99);
} catch (MyException e) {
System.out.println("myexception "+e);//exception类中的toString方法用来打印e
}
}
public static void test(int aa) throws MyException {
System.out.println("aa进来");
if(aa>10){
throw new MyException(aa);
}
System.out.println("异常结束");
}
注意:
- 在catch的最后加一个catch(Exception e)来处理可能遗漏的异常
- 对不确定的代码可以加上try-catch处理潜在异常
- 尽量增加自己对异常的处理操作
- 尽量添加finally释放占用的资源