JAVA基础笔记(个人向)

JAVA基础笔记(个人向)

此笔记以B站up主遇见狂神说的【狂神说Java】Java零基础学习视频通俗易懂视频来总结学习的

Java三大版本

Java SE:标准版,桌面程序,新手入门

Java ME:嵌入式开发,基本已凉

Java EE:企业级开发,web端,服务器

Java SE —> Java EE —>就业

JDK,JRE,JVM

JDK: Java Development Kit(java开发者工具)

​ 包含JRE和JVM,增加了一些开发程序时用到的工具

JRE: Java Runtime Environment(java运行时环境)

​ 包含JVM,有了这个就可以运行java程序

​ java库

JVM: Java Virtual Machine(java虚拟机)

​ java底层环境,实现跨平台

​ 解释型,编译型

数据类型

类型 存储东西(栈中) 大小/字节 默认值
byte 数据 1 0
short 数据 2 0
int 数据 4 0
long 数据 8 0
float 数据 4 0.0
double 数据 8 0.0
char 数据 2 null
boolean 数据 1 flase
引用类型:String,对象类型 地址,堆中存数据 ~ null

内存理解

java内存个人理解

引用类型 变量名 = 实际内容

个人理解:所以==是比变量名内容(指向内容),equals是比实际内容

!注意!:

String s1 = "abc";	//若栈中有abc则将s1直接指向栈中的abc(相当于基本类型),不然才创建String对象
String s2 = new String("abc");	//直接在堆中创建String的对象并让s2指向它

类型转换

低————————————————————>高

byte,short,char—>int—>long—>float—>double

高到低强制转换

变量,作用域

long类型后加L

float类型后加f

public class Demo01 {

    //类变量,关键字static
    static int c=2500;

    //实例变量/成员变量:从属于对象,可以不初始化值,如果不自行初始化,值为该类型的初始值
    //布尔值默认为false
    //除了基本类型,其他默认都为null
    String name;
    int age;

    public static void main(String[] args) {

        //局部变量,必须声明和初始化
        int a=10;
        System.out.println(a);

        //实例变量,需实例化对象
        //实例化类!!!不是方法!!!
        Demo01 d1=new Demo01();
        System.out.println(d1.name);
        System.out.println(d1.age);

        //类变量,直接用
        System.out.println(c);
    }
}

常量

//final 常量名(大写) = 常量值
final PI = 56;

位运算

public class BitOperation {
    public static void main(String[] args) {
        /*位运算
        A = 0000 1011
        B = 1010 0001
        ------------------------------------------
        A&B:0000 0001   与运算,有0则0,全1则1
        A|B:1010 1011   或运算,有1则1. 全0则0
        A^B:1010 1011   异或运算,相同为0,不同为1
        ~A: 1111 0100   取反运算
        ~B: 0101 1110
		==========================================
        A = 0000 0001 = 1
        B = 0000 0010 = 2
        C = 0000 0011 = 3
        D = 0000 0100 = 4
        E = 0000 0101 = 5
        F = 0000 1000 = 8
        G = 0001 0000 = 16
        -------------------------------------------
        A<<1:0000 0010 = B  左移1位, *2
        D>>1:0000 0010 = B  右移1位, /2
		效率极高!!!
		
        所以2*8——>2*2*2*2——>2<<3=16
         */
        System.out.println(2<<3);
    }
}

JavaDoc

javadoc命令用来生成自己的API文档

/**
 * @author  作者名
 * @version 版本号
 * @since   指明需要最早使用的jdk版本
 * @param   参数名
 * @return  返回值情况
 * @throws  异常抛出情况
 */
public class Doc {
    public static void main(String[] args) {
    }
}

命令使用:

#javadoc [参数] 文件名
#参数:-encoding UTF-8	注释的编码为utf-8
#	  -charset UTF-8  字符集编码为utf-8
javadoc -encoding UTF-8 -charset UTF-8 Doc.java

Scanner对象(IO流记得关闭)

next():

//next()不能接受空格,将有效字符后的空格作为结束符,用hasNext()判断是否有输入
package com.eleike.scanner;

import java.util.Scanner;

public class Demon01 {
    public static void main(String[] args) {
        //引入Scanner包,创建Scanner对象接受键盘输入
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入:");
        //判断是否有输入,if判断语句可省略
        if(scanner.hasNext()){
            String str = scanner.next();
            System.out.println("输入的是:"+str);
        }
        //关闭io流
        scanner.close();

    }
}

nextLine():

//nextLine()将回车符作为结束符,接受结束符前全部字符,用hasNextLine()判断是否有输入
package com.eleike.scanner;

import java.util.Scanner;

public class Demon02 {
    public static void main(String[] args) {
        //引入包
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入:");
        //判断是否有输入,if判断可省略
        if(scanner.hasNextLine()){
            String str = scanner.nextLine();
            System.out.println("输入的数据是:"+str);
        }
        //关闭io流
        scanner.close();
    }
}

nextInt(), nextLong(), nextFloat()...

.......判断输入类型的方法有很多...

For循环

结构

/*
for(初始值1,初始值2...;判断条件;数值变化1,数值变化2...){
	内容语句...
}
*/

for(int i = 0,j = 10; i < 10; i++,j++){
    System.out.println(i+","+j);
}

For-Each增强For循环(快速遍历数组集合)

package com.eleike.loop;
//快速:array.for 
public class ForDemon02 {
    public static void main(String[] args) {
        int[] number={10,20,30,40,50};
        //增强for循环
        for(int x:number){
            System.out.println(x);	//x为数组中各元素值
        }
    }
}

outer标签

//100~150中的质数
package com.eleike.base;

public class OuterDemo {
    public static void main(String[] args) {
        //outer标签,添加标记
        outer:for (int i = 100; i <= 150; i++) {
            for (int j = 2; j < i/2; j++) {
                if(i % j == 0) {
                    //跳转到outer标签位置
                    continue outer;
                }
            }
            System.out.print(i+" ");
        }
    }
}

方法重载

方法名必须相同,形参必须不同(形参个数,类型,顺序)

命令行传参(main方法传参)

main方法也可传参

package com.eleike.method;

//命令行传参
public class Demo01 {
    //main方法也可以传参
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            //打印输出传入到main方法里的内容
            System.out.println("args["+i+"]:"+args[i]);
        }
    }
}

编译执行文件:

E:\Project\JavaBase\src\com\eleike\method>javac -encoding utf-8  Demo01.java	#注意文件路径
E:\Project\JavaBase\src> java com.eleike.method.Demo01 hello world	#注意路径和包名	传入参数hello world
args[0]:hello
args[1]:world
#输出了传入的"hello world"

可变参数(形参)

package com.eleike.method;

public class Demo02 {
    public static void main(String[] args) {
        Demo02 demo02 = new Demo02();	//实例化类/对象,而不是方法
        demo02.test(1,2,3,4,5,6,7,8,9); //传入数量不固定,但类型需相同
    }
    /*
    可变参数,实质为数组
    在指定的类型后加省略号(...)来实现
    一个方法中只能有一个可变参数,且它必须为最后一个参数
     */
    public void test(int a,int... i){
        for (int x : i) {
            System.out.println(x);
        }
    }
}

数组

创建

package com.eleike.array;

public class ArrayDemo01 {
    public static void main(String[] args) {
        //静态初始化,声明+创建+赋值
        int[] sum1 = {1,2,3,4,5};

        //动态初始化,声明+创建
        int[] sum2 = new int[10];
        //赋值
        sum[0]=10;
        sum[1]=11;
        sum[2]=12;
    }
}

Arrays类

java提供的数组类,包含操作数组的方法

package com.eleike.array;

//引入Arrays包
import java.util.Arrays;

public class ArrayDemo02 {
    public static void main(String[] args) {
        int[] a={1,2,3,59,64,1231,1,98,365};

        //Arrays.toString()方法:打印输出数组内容
        System.out.println(Arrays.toString(a));

        //Arrays.sort()方法:数组排序方法,默认升序
        Arrays.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

方法还有很多,详见jdk帮助文档

经典之冒泡排序

package com.eleike.array;
//引入Arrays包
import java.util.Arrays;

public class ArrayDemo03 {
    public static void main(String[] args) {
        int[] a={321,54,81,56,3,5,6,1,65,1,2154,589};
        sort(a);
        System.out.println(Arrays.toString(a));	//Arrays.toString()方法
    }
    //冒泡排序
    public static int[] sort(int[] arrays){
        int num = 0;
        //排序次数最多是数组长度-1次,即长度5的数组,排序4次即可完成
        for (int i = 0; i < arrays.length-1; i++) {
            //每次排序会确认一个最大或最小值,所以-i
            for (int j = 0; j < arrays.length-1-i; j++) {
                //前比后大交换位置,升序排序
                if(arrays[j]>arrays[j+1]){
                    num = arrays[j];
                    arrays[j] = arrays[j+1];
                    arrays[j+1] = num;
                }
            }
        }
        return arrays;
    }
}

稀疏数组(数组压缩)

当一个数组中大部分元素为0或为同一值的时候,可以使用稀疏数组来保存该数组

稀疏数组第一行存储原始数组的行,列,有效数据个数,之后每行存储有效数据的坐标(所在行和列)和值

所以稀疏数组的大小为 array[有效数据个数+1][3]

package com.eleike.array;
//稀疏数组
public class ArrayDemo04 {
    public static void main(String[] args) {
        //创建原始数组
        int[][] array1 = new int[15][15];
        array1[1][2]=11;
        array1[5][1]=25;
        array1[3][6]=23;
        array1[9][5]=86;
        array1[3][10]=6;
        System.out.println("原始数组为:");
        for (int[] ints : array1) {
            for (int anInt : ints) {
                if (anInt >= 10){
                    System.out.print(anInt+" ");
                }else{
                    System.out.print(anInt+"  ");
                }
            }
            System.out.println();
        }
        System.out.println("===========================================");
        
        int sum = 0;    //计算原始数组有效数据个数
        int sum2 = 0;   //计算原始数组每列长度
        int max = array1[0].length; //记录原始数组最长列
        for (int[] ints : array1) {
            sum2 = 0;
            for (int anInt : ints) {
                sum2++; //每有一个数据+1,计算列长
                if (anInt != 0){
                    sum++;  
                }
            }
            //此列长度比以往列长,则记录此列长度
            if (sum2 > max){
                max = sum2;
            }
        }
        System.out.println("有效值个数为:"+sum+"\n最长列为:"+max);
        //创建稀疏数组,长度为有效数据+1,列为3
        int[][] array2 = new int[sum+1][3];
        //稀疏数组第一行记录原始数据的行,列,有效数据个数
        array2[0][0] = array1.length;
        array2[0][1] = max;
        array2[0][2] = sum;
        int cont = 0;
        //遍历原始数组,记录每一个有效数据的坐标和值
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                if (array1[i][j] != 0){
                    cont++;
                    array2[cont][0] = i;
                    array2[cont][1] = j;
                    array2[cont][2] = array1[i][j];
                }
            }
        }
        System.out.println("转换后的稀疏数组为:");
        System.out.println("   行 |列 |值");
        //打印转化后的稀疏数组
        for (int i = 0; i < array2.length; i++) {
            System.out.print("["+i+"] ");
            for (int j = 0; j < array2[i].length; j++) {
                if (array2[i][j] >= 10){
                    System.out.print(array2[i][j]+" ");
                }else{
                    System.out.print(array2[i][j]+"  ");
                }
            }
            System.out.println();
        }
        System.out.println("===========================================");
        
        //根据稀疏数组还原原数组
        int[][] array3 = new int[array2[0][0]][array2[0][1]];   //原数组大小(行列)在稀疏数组第一行记录
        //将稀疏数组中记录的有效数据还原
        for(int i = 1; i < array2.length; i++) {
            array3[array2[i][0]][array2[i][1]] = array2[i][2];
        }
        //打印还原后的数组
        System.out.println("还原后的数组:");
        for (int[] ints : array3) {
            for (int anInt : ints) {
                if (anInt >= 10){
                    System.out.print(anInt + " ");
                }else{
                    System.out.print(anInt + "  ");
                }
            }
            System.out.println();
        }
    }
}

异常

  • 越界异常:ArrayIndexOutofBounds

static关键字

  • 被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了(跟类一起加载),就可以通过类名去进行访问。

  • 被static修饰的变量/方法被称为静态变量/静态方法

  • !!!static关键字不会影响到变量或者方法的作用域!!!

  • 初始化的顺序: 静态代码块 > 构造代码块(匿名代码块) > 构造函数

面向对象

OOP(Object-Oriented Programming):面向对象编程 OO:面向对象

面向过程:线性思维,第一步...第二步...第三步...

面向对象:物以类聚,分类思维

本质

以类的方式组织代码,以对象的方式组织(封装)数据

抽象的

三大特征

封装:封装数据,安全

继承:继承父类

多态:同一事物多种形态,不同对象执行相同方法结果不同

构造器

  • 类中的构造器也称之为构造方法

  • 一个类即使什么方法都不写也会有一个隐藏的默认的构造方法

  • 构造方法特点:

    • package com.oop.Demo01;
      
      public class Student {
          /*
          1.方法名必须与类名相同
          2.方法没有任何返回值(!不需要void修饰!)
          */
          public Student() {
          }
      }
      
  • 构造方法作用:

    • new关键字创建对象本质是调用构造方法
    • 初始化对象的值
  • 有参构造方法:

    • package com.oop.Demo01;
      
      public class Student {
          String name;
          //无参构造方法
          public Student() {
          }
          
      	//有参构造方法,实质是方法的重载
          //创建对象时会根据传入的参数选择对应的构造方法
          public Student(String name) {
              this.name = name;
          }
      }
      
    • 定义了有参构造方法后,如果想使用无参构造方法,那必须再显示的定义一个无参构造方法!!!

    • idea快捷键Alt+Insert,快速创建构造方法

封装(数据的隐藏)

属性私有,get/set

package com.oop.Demo02;
//主调用类
public class Application02 {
    //main方法,调用其他类
    public static void main(String[] args) {
        Person02 p1 = new Person02();
        p1.setName("eleike");
        p1.setAge(999);
        p1.setIdCode(370104155);
        System.out.println(p1.getName());
        System.out.println(p1.getAge());
        System.out.println(p1.getIdCode());
    }
}
////////////////////////////////////////////////////////////////
package com.oop.Demo02;
/*
    1.提高程序安全性,保护数据
    2.隐藏代码的实现细节
    3.统一接口
    4.系统可维护增加了
*/
//抽象类
public class Person02 {
    //private:私有的
    private String name;    //姓名
    private int age;        //年龄
    private int idCode;     //身份证号
    //私有属性无法直接访问,所以需要提供一些public的get,set方法

    //获得name数据
    public String getName() {
        return name;
    }

    //设置name数据值
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        //设置属性值的时候可以对设置的值进行判断
        if (age > 120 || age < 0){  //年龄太高或太低不合理
            this.age = 3;
        }else{
            this.age = age;
        }
    }

    public int getIdCode() {
        return idCode;
    }

    public void setIdCode(int idCode) {
        this.idCode = idCode;
    }
}

继承(extends)

构造方法不能被继承

结构

关键字extends

package com.oop.Demo03;

public class Application03 {
    //主方法
    public static void main(String[] args) {
        Student03 std1 = new Student03();
        //子类可使用继承自父类的公共属性和方法
        std1.say();
        System.out.println(std1.money);
        std1.setName("eleike");
        System.out.println(std1.getName());
    }
}
////////////////////////////////////////////////////////
package com.oop.Demo03;
//父类Person
public class Person {
    //私有属性或方法不能继承
    private String name;
    //公共属性或方法可以继承
    public int money = 10_0000_0000;

    //公共属性或方法可以继承
    public void say(){
        System.out.println("我是父类");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
////////////////////////////////////////////////////
package com.oop.Demo03;

//关键字extends
//子类Student03,继承自父类Person
public class Student03 extends Person{

}

  • java只有单继承,没有多继承,即一个子类只能有一个父类,但一个父类可有多个子类

  • 所有类都会直接或间接的继承自Object类

    image-20211125225008527

  • IDEA快捷键(ctrl+h)查看类继承关系图

super关键字

super特点:

  • super用来调用父类的属性或方法
  • !!!super必须出现在子类的方法或构造方法中!!!只能写在方法中!!!
  • this和super不能同时调用构造方法

与this相比:

  • 前提
    • this没有继承也可使用
    • super只能用在有继承的子类中
  • 构造方法
    • this(); 本类的构造方法,可减少代码数量
    • super();表示父类的构造方法
package com.oop.Demo04;
//主方法,程序入口
public class Application04 {
    public static void main(String[] args) {
        Student04 std4 = new Student04();
        std4.say();
    }
}
////////////////////////////////////////////////////////
package com.oop.Demo04;
//父类
public class Person04 {

    String name;

    public Person04() {
        System.out.println("父类无参构造执行!");
    }

    public Person04(String name) {
        this.name = name;
        System.out.println("父类有参构造执行!");
    }

    public void print(){
        System.out.println("This is Person!");
    }
}
/////////////////////////////////////////////////////////
package com.oop.Demo04;
//子类,继承Person04
public class Student04 extends Person04{
    //无参构造
    public Student04() {
        //隐藏代码:super()默认调用父类无参构造,要在第一行
        //也可以调用父类的有参构造:super("zhangsan");
        super();
        //this()默认调用自身的构造方法,不能与super()同时用
        System.out.println("子类无参构造执行!");
    }

    public void print(){
        System.out.println("This is student!!!");
    }

    public void say(){
        super.name = "Eleike";  //修改父类属性
        System.out.println(super.name); //输出父类属性
        this.print();   //调用自身的print()方法
        super.print();  //调用父类的print()方法
    }
}

子类对象创建过程是先执行父类的无参构造,再执行子类的无参构造

方法的重写

只能重写方法

构造方法不能被继承,所以也无法被重写

概念:

  • 需要有继承关系,子类重写父类的方法!
  • 方法名必须相同
  • 参数必须相同
  • 修饰符的范围可以扩大但不能缩小,修饰符范围:public>Protected>Default>private
  • 抛出的异常的范围可以缩小但不能扩大

!!!重写子类的方法与父类一致,方法体不同!!!

package com.oop.Demon05;
//程序入口
public class Application05 {
    public static void main(String[] args) {
        Student05 std5 = new Student05();
        std5.say();
    }
}
///////////////////////////////////////////////////////
package com.oop.Demon05;
//父类
public class Person05 {
    public void say(){
        System.out.println("Person05说话了!");
    }
}
//////////////////////////////////////////////////////
package com.oop.Demon05;
//子类
public class Student05 extends Person05{
    //Override重写
    @Override   //注解,有功能
    public void say() {
        //重写的方法
        System.out.println("Student05说话了");
    }
}

为什么重写:

  • 父类的功能子类不需要
  • 父类的功能子类不满足

IDEA快捷键:ALT+Insert —>Override

不能重写的方法:

  • static:静态方法,属于类,不属于实例
  • final:常量
  • private:私有方法

多态

方法的多态,没有属性的多态

概念

一个对象的实际类型是确定的,但可以指向的引用类型就不确定了(引用类型和实际类型必须要有继承关系)

//引用类型 a = new 实际类型();
Student s = new Student();

父类的引用指向子类的情况:

B继承A,A a1 = new B();

调用方法时:

  • 静态方法:
    • 优先调用自身引用类型内对应的方法
    • 父类没有则无法调用,调用子类需强行转换成子类引用类型
  • 动态方法:
    • 子类没有重写则调用父类自身方法
    • 子类重写了父类方法,则调用子类重写后的方法

!!!对象能调用的方法,主要看对象左边的引用类型!!!

package com.oop.Demo07;
//程序入口
public class Application07 {
    public static void main(String[] args) {
        //Student07能调用的类型只有自己独有的和继承自父类的
        Student07 std1 = new Student07();
        
        //父类的引用指向子类
        //Person07 父亲类,可以指向子类但不能直接调用子类独有的方法(需要强转)
        Person07 std2 = new Student07();
        Object std3 = new Student07();  //Object是所有方法的父类

        //对象能执行哪些方法,主要看对象左边的引用类型拥有哪些方法
        //静态方法(无法重写)调用,优先调用自己引用类型内的方法
        std2.say();
        std1.say();
        //子类没有重写的方法调用父类方法
        std1.eat();
        std2.eat();
        //子类重写了的父类方法,则调用子类重写后的方法
        std1.run();
        std2.run();
        //子类独有的方法只能子类调用
        std1.walk();
        ((Student07)std2).walk();   //父类调用需要强转类型
    }
}
///////////////////////////////////////////////////////////////
package com.oop.Demo07;
//父类
public class Person07 {
    //父类的静态方法
    public static void say(){
        System.out.println("Person07说话!");
    }
	//子类有重写
    public void run(){
        System.out.println("Person07跑步!");
    }
	//子类没有重写
    public void eat(){
        System.out.println("Person07吃东西");
    }
}
////////////////////////////////////////////////////////////////
package com.oop.Demo07;
//子类
public class Student07 extends Person07{
    //自类的静态方法
    public static void say(){
        System.out.println("Student07说话!");
    }
    //继承方法重写
    @Override
    public void run() {
        System.out.println("Student07跑步!");
    }
	//子类独有方法
    public void walk(){
        System.out.println("Student07散步!");
    }
}

instanceof关键字

作用:

X instanceof Y 用来判断X类与Y类是否有继承关系,输出true/false

是否能编译通过取决于X的引用类型与Y是否有继承关系

是否输出true取决于X的实际类型是否是Y的子类型

类型转换

父类-------------->子类

高-------------------->低

高到低转换需要强转,父类要使用子类的方法需要强转

static

修饰方法,属性,被修饰的方法和属性随着类的加载同时被加载,且只执行一次

创建对象:静态(static)代码块>匿名代码块>构造方法

可修饰包

final

修饰引用、方法和类

被修饰的引用为常量

被修饰的方法无法被重写

被修饰的类无法被继承,为最终类,没有子类

abstract(抽象类)

修饰类和方法

修饰类(抽象类):

  • 被修饰的类不能被实例化(即不能直接new 抽象类();),只能创建其子类对象
  • 抽象类可以写普通方法,可以没有抽象方法

修饰方法(抽象方法):

  • 抽象方法只有方法名,没有方法实现,例 public abstract void walk();
  • 抽象方法必须必须在抽象类中
  • 抽象方法必须在子类中被重写,除非子类也是抽象类

接口(interface)

  • interface修饰的类为接口
  • 接口中属性默认修饰符public static final,所以只有常量
  • 接口中方法默认修饰符public abstrace
  • 接口中只能写抽象方法,不能写具体实现
  • 不能直接实例化(不能直接new),要创建其接口实现类的对象,同抽象类
  • 接口可以多继承,implements来继承,","逗号隔开
  • 其接口实现类(继承接口的类)必须实现方法
package com.oop.Demo09;
//程序入口
public class Application09 {
    public static void main(String[] args) {
        Student09 student09 = new Student09();
        student09.say("Eleike");
    }
}
/////////////////////////////////////////////////////////////////////////
package com.oop.Demo09;
//接口1
public interface Person09 {
    //接口冲属性默认修饰符为public static final,所以接口中定义的属性都是常量
    int age = 99;
    //接口中方法默认修饰符是public abstrace
    void say(String name);  //其实为public abstrace void say(String name);
    public abstract void eat();
    void walk();
}
//////////////////////////////////////////////////////////////////////////
package com.oop.Demo09;
//接口2
public interface Father09 {
    void run();
}
//////////////////////////////////////////////////////////////////////////
package com.oop.Demo09;
//接口实现类
public class Student09 implements Person09,Father09{	//implements继承
    //必须要重写接口内所有方法
    @Override
    public void run() {
    }
    
    @Override
    public void say(String name) {
        System.out.println(name);
    }
    
    @Override
    public void eat() {
    }
    
    @Override
    public void walk() {
    }
}

!!!类内调用子类方法实现创建并返回父类类型对象!!!

父类中设置静态方法,方法内调用子类(实现类)创建子类对象的方法来返回一个子类对象(可自动转化为父类类型对象),实现抽象类不必手动调用其实现类即可实例化(并非真的绕开了抽象类不能实例化的问题,只是方法内自动帮我们调用了其实现类)

像是日期类的java.util.Calendar,Calendar类中的Calendar.getInstance()方法就是此种用法

实例1:

package com.test.test03;

public class Application03 {
    //程序入口
    public static void main(String[] args) {
        TestPerson03 tp1 = TestPerson03.getInstance();	//调用抽象方法内的实例化方法
        System.out.println(tp1);
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////
package com.test.test03;
//父类,抽象类,不可直接实例化
public abstract class TestPerson03 {

    private String name;
    private int age;

    public abstract void say();		//抽象方法,无方法体
    public abstract void walk();	//抽象方法,无方法体
	
    //创建子类对象方法,返回值是TestPerson03类型
    public static TestPerson03 getInstance(){
        return TestSon03.createTestPeron03("Eleike",15);	//调用子类中创建对象的方法
//        return new TestSon03().createTestPeron03("eleike",88);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "TestPerson03{" +
                "name='" + name + '\'' +
                ", a=" + age +
                '}';
    }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
package com.test.test03;
//子类,TestPerson03的实现类
public class TestSon03 extends TestPerson03{
    @Override
    public void say() {
    }

    @Override
    public void walk() {
    }
	//创建自身对象的方法
    public static TestPerson03 createTestPeron03(String name,int age){
        TestSon03 ts1 = new TestSon03();
        ts1.setAge(age);
        ts1.setName(name);
        return ts1;	//返回一个自身类型对象
    }
}

内部类

内部类

package com.oop.demo10;
//程序入口
public class Application10 {
    public static void main(String[] args) {
        Person10 per10 = new Person10();
        //实例化内部类:通过这个外部类来实例化内部类
        Person10.Inner in = per10.new Inner();	//实例化内部类
        in.in();
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////
package com.oop.demo10;

public class Person10 {
    private int age = 10;

    public void out(){
        System.out.println("这是外部类!");
    }
    
    //内部类,内部类可以访问外部类的私有属性
    //加上static就是静态内部类
    public class Inner{
        public void in(){
            System.out.println("这是内部类!");
            System.out.println(age);
        }
    }
}

局部内部类

package com.oop.demo10;

public class Student10 {
    public void eat(){
        //局部内部类,写在方法内
        class A{
            public void say(){
                System.out.println("局部内部类方法");
            }
        }
    }
}

匿名内部类

匿名内部类,没有名字初始化类,不用将实例保存到变量中

package com.oop.demo10;
//一个java类文件中只能有一个public class,但可以有多个class
public class Application10 {
    public static void main(String[] args) {
        //匿名内部类,没有名字初始化类,不用将实例保存到变量中
        new Sthool().teacher();	//直接使用方法
        //匿名实例接口
        User user = new User() {
            @Override
            public void name() {
            }
        };
    }
}

class Sthool{
    public void teacher(){
        System.out.println("老师");
    }
}

interface User{
    void name();
}

异常

异常类分为两大类

Throwable(是所有类的超类,包含所有异常和错误):

  • Error:错误
  • Exception:异常
    • IOException:检查性异常
    • RuntimeException:运行时异常

范围:大————————————————————>小

​ Throwable—>Exception—>Error—>具体异常类

try/catch/finally

IDEA快捷键:Ctrl+Alt+t

finally可以跨过return和throw执行里面的代码

单个异常处理(单catch)

package com.exception;
//0不能为除数,会抛出一个ArithmeticException类异常
public class Demo01 {
    public static void main(String[] args) {
        int a = 1,b = 0;
        try {   //监控区域,监控可能出现的异常
            System.out.println(a/b);
        } catch (ArithmeticException e) {     //catch(想要捕获的异常类型),捕获异常并做相应处理
            //e.printStackTrace(); 打印错误的栈信息
            System.out.println("0不能为除数");
        } finally {     //无论是否有异常,最终都会执行的代码块,通常用来善后工作
            System.out.println("程序结束");
        }
    }
}

多个异常处理(多catch)

若要捕获多个异常:从小到大的去捕获

package com.exception;

public class Demo02 {
    public static void main(String[] args) {
        int a = 1,b = 0;
        new Demo02().a();
        //多个catch处理,catch中的异常类型要从小到大的去捕获
        try {
            new Demo02().a();	//匿名类直接调用方法
        } catch (ArithmeticException e) {
            System.out.println("ArithmeticException异常");
        } catch (Error e1) {
            System.out.println("Error异常");
        }catch (Exception e2) {
            System.out.println("Exception异常");
        }catch (Throwable t) {
            System.out.println("Throwable异常");
        }finally {
            System.out.println("异常处理结束");
        }
    }
    //下面两个方法互相调用会出现堆栈溢出的错误(StackOverflowError)
    public void a(){
        b();
    }
    public void b(){
        a();
    }
}

!!try/catch总结!!

  • try-catch放在循环里面是,如果出现异常,执行完异常再次执行语句时,若没有重新进行变量的定义,try语句仍然判断上一次的输入,即在此出现异常,如此往复,造成无限循环(所以创建Scanner要放在循环里面)。
  • try-catch语句放在循环外面,出现异常会终止循环。
  • finally一定会执行,可用来跳出循环。

实例1

package com.date;

import java.util.Scanner;

public class PrintCalendar {
    public static void main(String[] args) {

        while (true){
            System.out.println("请输入数字:");
            Scanner scanner = new Scanner(System.in);	//放在循坏外就会无限循坏
           try {
                int number =scanner.nextInt();	//只接受int型
            } catch (Exception e) {
                System.out.println("输入异常,请重新输入:");
                continue;
            }
           scanner.close();	//此条语句不能放在catch或finally语句中,否则也是无限循环
           System.out.println(number);	//输出输入内容
           break;
        }
    }
}

throw

主动抛出异常,一般用在方法内,不常用

throw相当于return,使程序跳出当前方法,除非后面有finally代码块

package com.exception;

/**
 * @author new wei
 * @date 2021/12/2 23:33
 */
public class Demo03 {
    public static void main(String[] args) {
        try {
            new Demo03().test03(1,0);
        } catch (Exception e) {
            System.out.println("异常处理了");
        }
    }
    //假设这个方法中处理不了这个异常,主动抛出一个异常
    public void test03(int a,int b){
        if (b == 0){
            //要具体
            throw new ArithmeticException();    //throw主动抛出异常,一般在方法内使用
        }
    }
}

throws

方法主动抛出异常,一般用在方法上

package com.exception;

public class Demo04 {
    public static void main(String[] args) {
        try {
            new Demo04().test04();
        } catch (Exception e) {
            System.out.println("捕获到异常");
        }
    }
    //test04方法主动抛出一个Exception异常
    public void test04() throws Exception{
        throw new Exception();
    }
}

自定义异常

创建自定义异常只需要创建一个类继承自Exception,类中描述内容,最终toString();输出错误描述信息

package com.exception;

public class Test01 {
    public void say(int a) throws MyException{  //主动将方法中的异常向上抛出给调用者
        if (a > 10){
            //判读后主动抛出异常
            throw new MyException(a);   //用异常的有参构造器
        }
    }
	//程序入口
    public static void main(String[] args) {
        try {
            new Test01().say(11);
        } catch (MyException e) {
            System.out.println(e);  //直接打印e相当于打印e.toString();
        }
    }
}
////////////////////////////////////////////////////////////////////////////////////////////
package com.exception;

//继承自Exception类
public class MyException extends Exception{
    private int a;

    //有参构造器,此类中没有无参构造器,所以无法使用无参构造
    public MyException(int a) {
        this.a = a;
    }

    @Override
    public String toString() {  //toString是默认返回创建者对该异常定义的错误描述
        return "MyException{" + "a=" + a + '}';
    }
}

杂记(常看)

  • 除类名是首字母大写加驼峰规则,其他都是首字母小写加驼峰规则(常量全大写,字母下划线隔开)

  • 除了八大基本类型其他都是引用类型,例:数组,string

  • BigDecimal 数学工具类,银行相关有业务,完善浮点数比较问题

  • Unicode编码表

  • 拼接字符串"+":

    • 前有String类型会变成拼接字符串:a=10,b=20,""+a+b=1020
    • String类型放到后面正常计算:a=10,b=20,a+b+""=30
  • equals:判断字符串是否相等:

    • //equals只判断内容,不比较内存地址	"=="会判断两个对象在内存中的首地址,尽量不要用他判断字符串和对象
      string s;
      s.equals("Hello")	//判断字符串s是否等于Hello,
      
  • javac命令遇到错误: 编码GBK的不可映射字符问题:

    • javac -encoding utf-8 <文件名>	#编码错误导致
      
  • 在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字

  • 修饰符范围:public>Protected>Default>private

  • 一个java类文件中可以有多个class类,但是只能有一个public class类

  • System.exit(0);停止程序

  • 构造方法不要加void修饰

  • throw和return同时出现会报错(Unreachable statement),但是finally可以让他们并存,最终finally里的内容覆盖前者,即使所描述内容不同

小问题

  1. int a = 15中,变量名a是指向15的地址(或是15的Unicode代码位?或其他?),还是就是15这个值
    • 栈中的数据是共享的,所以编译器首先创建变量为a的引用,然后在栈中查找是否有15这个值,没有就将15存放到栈中并让a直接指向15;若栈中存在15,则让a直接指向15
  2. Integer自动拆包后赋值给int类型,然后两方用==比较为什么结果为true?Integer类型不是对象吗?不应该是指向地址吗?
    • int类型和Integer对象用==比较时Integer对象会自动拆箱,所以实际上比较的是Integer对象中int类型的成员常量value
posted @ 2021-12-03 17:11  Eleike  阅读(50)  评论(0)    收藏  举报