Java基础篇

java基础

Java的特性优势

  • 简单性
  • 面向对象
  • 可移植性
  • 高性能
  • 分布式
  • 动态性 【反射机制】
  • 多线程
  • 安全性 【异常机制】
  • 健壮性

java三大版本

  • write once 、run anywhere
  • javaSE:标准版 【桌面程序、控制台开发....】
  • javaME:嵌入式开发【手机,小家电....】 用的人很少了
  • javaEE:E企业级开发【web端,服务器开发.....】

JDK JRE JVM

JVM ---》 JRE ---》 JVM

java程序运行机制

  • 编译型: 把程序全部翻译成计算机可以执行的语言 compile 编译器

  • 解释性: 边执行边解释

  • 程序运行机制:

    • 源程序(.java)---》 java编译器---》字节码(.class) ---》

      类装载器---》字节码检验器---》解释器----》操作系统平台

标识符

  • java标识符大小写敏感;
  • java标识符只能以字母 $ _ 开头

数据类型

  • 强类型语言

    要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用

  • 弱类型语言

浮点数

float f = 0.1f;
double d = 1/10;
System.out.println(f==d);//fasle

float d1 = 23232323231f;
float d2 = d1+1;
System.out.println(d1==d2);//true
  • float 有限 离散 舍入误差 大约 接近但不等于
  • double
  • 最好完全避免使用浮点数进行比较
  • BigDecimal 类 数学用具类 大数据类 【用这个】

字符

char c1 ='a';
char c2 = '中';
System.out.println(c1);// a
System.out.println((int)c1);// 97  强制类型转换
//所有的字符本质还是数字
//编码 Unicode 有表:(97 = a  65 =A) 2字节  0 - 65526
// U0000 UFFFF
char c3 = '\u0061'
System.out.println(c3);// a

//转义字符
// \t 制表符
// \n 换行符
System.out.println("Hello\tworld");
System.out.println("Hello\nworld");

//看一个e.g.
String sa = new String("hello world");
String sb = new String("hello world");
System.out.println(sa==sb);//false

String sc = "hello world";
String sd = "hello world";
System.out.println(sc==sd);//true

类型转换

  • 由于Java是强类型语言,所以要进行有些运算的时候,需要用到类型转换

    低 ---------------------到----------------------高

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

  • 强制类型转换 高 赋值 到 低 [会有内存溢出 和 精度 问题]

  • 自定类型转换 低 赋值 到 高

int i = 128;
byte  b = (int) i;//内存溢出  -128

double d = i;

//操作比较大的输的时候。注意溢出问题
int money = 10_0000_0000;//JDK7 新特性 数字之间可以用下划线分割
int years = 20;
int total = money * years; // -147483648,计算的时候溢出了
long total2 = money * years;//默认是int 转换之前还是int 就有问题了
 
long  total3 = money * ((long)years);//先把一个数转化为long  √

变量

变量作用域

  • 类变量 必须有static
  • 实例变量
  • 局部变量

常量

  • 用final来定义 一般名大写

运算符

  • 算术运算符 : + - * / % ++ --
		int e = 3;
        int f = e++; //执行这行代码,先给f赋值,在自增
        System.out.println(e);//4
        int g = ++e;//执行这行代码,先自增,后给g赋值
        int h = e++;//先赋值,在自增
        System.out.println(e);//6
        System.out.println(f);//3
        System.out.println(g);//5
        System.out.println(h);//5

		// 字符串连接符   +    
		int a = 10;
		int b = 20;
        System.out.println(""+a+b);//1020
        System.out.println(a+b+"");//30
  • 赋值运算符 : =
  • 关系运算符 : > < >= <= == != instanceof
  • 逻辑运算符 : && || ! 与或非

[注:] &&: 有0 返回 || : 有 1 返回 --------- 短路机制

  • 位运算符 : & | ^ ~ >> << >>>(了解)
 System.out.println(2<<4);//<<左移乘2  >>右移除2
  • 条件运算符 : ? :
  • 扩展赋值运算符: += -= *= /=

JavaDos

    /**
     * @author shuang 作者
     * @version 1.0  版本号
     * @since 1.8  指明需要最早使用的JDK版本
     * @param in  参数名
     * @return 返回值情况
     * @throws   异常抛出情况
     */
    public String test(String in){
        return in;
    }
>javadoc  -encoding utf-8 -charset  utf-8 Doc.java
1、在cmd中运行上面命令会生成在线文档 点击index.html 可查看
2、也可以用IDEA生成javaDoc文档

Java流程控制

Scanner对象

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("第一次输入数据:");//hei baby
        // nextLine输出回车之前的数据  以回车分割
        String str = scanner.nextLine();
        System.out.println(str);//hei baby   
        System.out.println("第二次输入数据:");//hello  world
        // next输出空格之前的数据  以空格分割
        str = scanner.next();
        System.out.println(str);//hello
        scanner.close();
    }

示例:

    public static void main(String[] args) {
        //输入多个数字 求总和 平均值 每输入一个数字回车,通过非法数字来结束输入输出执行结果
        Scanner scanner   = new Scanner(System.in);
        double sum = 0;
        int m = 0;
        System.out.println("请输出数据:");
        while (scanner.hasNextDouble()){
            double x =  scanner.nextDouble();
            m++;
            sum+=x;
            System.out.println("输入了第【"+m+"】个数据 当前总和为:"+sum);
        }
        System.out.println(m+"个数总和:"+sum);
        System.out.println(m+"个数平均值:"+(sum/m));
        scanner.close();
    }

结果:

请输出数据:
36
输入了第【1】个数据 当前总和为:36.0
42
输入了第【2】个数据 当前总和为:78.0
7.6
输入了第【3】个数据 当前总和为:85.6
a
3个数总和:85.6
3个数平均值:28.53333333333333

顺序结构

  • def:语句与语句之间是按从上到下的顺序进行的,它是由若干依次执行的处理步骤组成的,它是任何一个算法都离不开的一种基本算法结构

选择结构

  • if单选择结构
if(布尔表达式){
    // 布尔表达式为true
}
  • if双选择结构
if(布尔表达式){
    // 布尔表达式为true
}else{
    // 布尔表达式为false
}
  • if多选择结构
if(布尔表达式1){
    // 布尔表达式1为true
}else if(布尔表达式2){
    // 布尔表达式2为true
}else if(布尔表达式3){
    // 布尔表达式3为true
}else if(布尔表达式4){
    // 布尔表达式4为true
}else{
    // 以上布尔表达式都不为true 执行代码
}

示例:

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入成绩:");
        int score = scanner.nextInt();
        if (score == 100){
            System.out.println("恭喜~~满分~~");
        }else if (score >= 90 && score < 100){
            System.out.println("A级");
        }else if (score >= 80 && score < 90){
            System.out.println("B级");
        }else if (score >= 70 && score < 80){
            System.out.println("C级");
        }else if (score >= 60 && score < 70){
            System.out.println("D级");
        }else if (score >= 0 && score < 60){
            System.out.println("不及格");
        }else {
            System.out.println("成绩不合法!!!");
        }
        scanner.close();
    }

结果:

请输入成绩:
100
恭喜~~满分~~
  • switch多选择结构
switch(expression){
    case value:
        //语句
        break;//可选
    case value:
        //语句
        break;//可选
    case value:
        //语句
        break;//可选
    default://可选
        //语句
}
//注: case标签 必须为 字符串常量或字面量 
//了解一下反编译    java ---- 字节码  ---- 反编译(IDEA) --- java

反编译(IDEA)示例

查看工程结构 projectStructure --- project ---project compiler output

可以找到.class文件 --- 右键任意文件 --- show in explorer(打开目录) ---

把.class文件拷贝到此目录下 --- IDEA把字节码反编译为java

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package struct;

public class Demo03 {
    public Demo03() {
    }

    public static void main(String[] args) {
        char grade = 108;
        switch(grade) {
        case 65:
            System.out.println("优秀");
            break;
        case 66:
            System.out.println("良好");
            break;
        case 67:
            System.out.println("及格");
            break;
        case 68:
            System.out.println("很差");
            break;
        case 69:
            System.out.println("挂科");
            break;
        default:
            System.out.println("未知等级!");
        }
    }
}

循环结构

  • while循环
while(布尔表达式){
    //布尔表达式true
}
//注:大多数情况会让循环停止下来,需要让表达式失效方式来结束循环;

示例:

    public static void main(String[] args) {
        // 1-100 求和
        int i = 0;
        int sum = 0;
        while (i<100){
            i++;
            sum = sum + i;
        }
        System.out.println(sum);//5050
    }
  • do while 循环

do whlile 和 while 相似,不同的是 do while 循环至少执行一次

do{
    //代码语句
}while(布尔表达式)
  • for循环
    • for循环语句是支持迭代的一种结构,是最有效,最灵活的循环语句
for(初始化;布尔表达式;更新){
  //代码语句  
}

示例1:

 public static void main(String[] args) {
        // 0-100 奇数偶数和
        int oddSum = 0;
        int evenSum = 0;
        for (int i = 0; i < 100; i++) {
            if(i% 2 == 0){
                evenSum+=i;
            }else {
                oddSum+=i;
            }
        }
        System.out.println("偶数和:"+evenSum);
        System.out.println("奇数和:"+oddSum);
    }

结果1:

偶数和:2450
奇数和:2500

示例2:

public static void main(String[] args) {
        //输出 1- 100 之间能被5整除的数,并且每行输出3个
        for (int i = 1; i <= 100; i++) {
            if(i%5 == 0){
                System.out.print(i + "\t");
            }
            if (i%15 == 0){
                System.out.println();
            }
        }
    }

结果2:

5	10	15	
20	25	30	
35	40	45	
50	55	60	
65	70	75	
80	85	90	
95	100	

示例3:

    public static void main(String[] args) {
        //打印九九乘法表
        for (int i = 1; i < 10; i++) {
            for (int j = 1; j < i+1; j++) {
                System.out.print(j+"*"+i+"="+(i*j)+"\t");
            }
            System.out.println();
        }
    }

结果3:

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	
  • 增强for循环
    • jdk5引入主要用于数组或集合的增强型for循环
for(声明语句 : 表达式){
    //代码句子
}
  • break 与 continue

    break:强制退出循环 continue : 终止某一次循环

练习

    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方法详解

e.g :System.out.println() 类System中out对象的println()方法

  • 一个方法只能完成一个功能 (原子性),这样利于我们后期的扩展。

方法的重载

  • 重载就是在一个类中,有相同的函数名称,但形参不同的函数。
  • 方法的重载的规则
    • 方法名称必须相同
    • 参数列表必须不同[个数不同、或类型不同,参数排列顺序不同等]
    • 方法的返回值可相同可不同
    • 仅仅返回值不同不足以成为方法的重载
  • 实现理论
    • 方法名称相同时,编译器会根据调用方法的参数个数,参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错

命令行传参(了解)

  • 找到class的路径直接cmd 运行javac xxx.class (没问题) ---> java xxx 汇报错error:找不到或无法加载主类。

  • 必须回到src文件夹通过包名去执行,并且可以给定参数

可变参数

  • 从jdk1.5开始,java支持传递同类型的可变参数给一个方法
  • 在方法声明中,在指定参数类型后面一个省略号(...)
  • 一个方法中只能指定一个可变参数,它必须时方法的最后一个参数,任何普通的参数必须在它之前声明

示例:

public class Demo04 {
    public static void main(String[] args) {
        printMax(33,5.6,4.77,53.7);
    }

    public  static void printMax(double... numbers){
        if (numbers.length == 0){
            System.out.println("数组为空");
            return;
        }
        double result =numbers[0];
        for (int i = 1; i < numbers.length; i++) {
            if (numbers[i] > result){
                result = numbers[i];
            }
        }
        System.out.println("最大的数是:"+result);
    }
}

结果:

最大的数是:53.7

递归

  • 递归就是自己调用自己
  • 递归结构包含两个部分
    • 递归头:什么时候不调用自身方法,如果没有头,将陷入死循环
    • 递归体:什么时候需要调用自身的方法

示例

public class Demo06 {
    public static void main(String[] args) {
        System.out.println(fun(4));
    }
    //递归求阶乘
     public static int fun(int n){
        if (n == 1){
            return 1;
        }else {
            return n*fun(n-1);
        }
     }
}

结果:

24

练习

写一个计算器 下面这个例子需要优化

public class Calculator {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while(true){
            System.out.println("请输入表达式");
            double x = Double.parseDouble(scanner.nextLine());
            String ch = scanner.nextLine();
            double y = Double.parseDouble(scanner.nextLine());
            double result =0;
            switch (ch){
                case "*":
                    result =cheng(x,y);
                    break;
                case "/":
                    result =chu(x,y);
                    break;
                case "+":
                    result=add(x,y);
                    break;
                case "-":
                    result= sub(x,y);
                    break;
                default:
                    System.out.println("输入运算符号错误!");
                    break;
            }
            System.out.println(result);
        }

    }

    public static double add(double x,double y){
        return  x+y;
    }

    public static double sub(double x,double y){
        return x-y;
    }
    public static double cheng(double x,double y){
        return x*y;
    }
    public static double chu(double x,double y){
        return x/y;
    }

}

结果:

请输入表达式
3
+
8.6
11.6
请输入表达式
4
*
6
24.0
请输入表达式
6
/
3
2.0
请输入表达式 

坑:next系列函数与nextLine连用有问题

  • next() nextInt() nextDouble() ... next系列函数 读缓存时会把回车终止符留在缓存区,下次遇到nextLine会遇到堵孔情况

数组

  • 数组是相同类型数据的有序集合
  • 数组描述的是相同类型的若干个数据,按照一定的先后顺序排列组合而成(看你放数据的顺序哦)
  • 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们
  • 数组的声明与创建
//方式一
int[] numbers;//声明 一个数组
numbers = new int[10]// 创建一个数组
numbers[0] = 10;//赋值
//方式二
int[] nums = {10,10,20,10};   
  • 内存分析

  • 数组的四个基本特点

    • 长度是确定的,数组一旦被创建,它的大小就是不可以改变的
    • 元素必须是相同类型,不允许出现混合类型
    • 数组中的元素可以是让任意类型,包括基本类型(int)和引用类型(Man)
    • 数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中 (只要是new出来的都在堆中)
  • 数组边界

ArrayIndexOutOfBoundsException:数组下标越界!

  • 数组使用

示例

public class ArrayDemo04 {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,55};
        for (int i : reverseV2(array)) {
            System.out.println(i);
        }
    }

    public static int[] reverse(int[] array){
        int[] result = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            result[array.length-1-i] = array[i];
        }
        return result;
    }

    public static int[] reverseV2(int[] array){
        int[] result = new int[array.length];
        for (int i = 0, j=array.length-1; i < array.length; i++,j--) {
            result[j]=array[i];
        }
        return result;
    }

}

结果:

55
4
3
2
1

多维数组

  public static void main(String[] args) {
        int[][] array = {{1,2},{2,4},{5,6}};
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                System.out.println(array[i][j]);
            }
        }
    }

Array

  • 数组的用具类java.util.Arrays
  • Arrays中的方法都是static静态的直接类点方法调用
  • 常用的功能
    • 给数组赋值:fill方法
    • 对数组排序: sort方法
    • 比较数据:用equals方法比较数组中元素值是否相等
    • 查找数组元素:binarySearch方法能对排序好的数组进行二分查找法操作

示例:

   public static void main(String[] args) {
        int[] a = {1,2,5464,353,46,55,415,766,6,64};
        System.out.println(a);//哈希值
        System.out.println(Arrays.toString(a));
        Arrays.sort(a);//排序 小到大
        System.out.println(Arrays.toString(a));
        Arrays.fill(a,0);//0去覆盖
        System.out.println(Arrays.toString(a));
        Arrays.fill(a,2,4,8);//对其中的一些值赋值
        System.out.println(Arrays.toString(a));

    }

结果:

[I@1b6d3586
[1, 2, 5464, 353, 46, 55, 415, 766, 6, 64]
[1, 2, 6, 46, 55, 64, 353, 415, 766, 5464]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 8, 8, 0, 0, 0, 0, 0, 0]

冒泡排序

  • 冒泡排序无疑是最为出名的排序算法之一,总共有八大排序
  • 冒泡的代码,两层循环,外层冒泡轮数,里层依次比较
  • 我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度是O(n2)

示例

import java.util.Arrays;

public class ArrayDemo07 {
    public static void main(String[] args) {
        int[] a = {1,45,43,54,2,53,58,64};
        System.out.println(Arrays.toString(sort(a)));
    }

    //冒泡排序
    //1、比较数组中,两个相邻的元素,如果第一个比第二个大,就交换位置
    //2、每一次比较,就会产生一个最大或者最小的数
    //3、下一轮可以 少一轮比较
    public static int[] sort(int[] array){
        //优化:设置一个标记位 如果已经有序 不用再比较了
        boolean flag = false;
        int temp = 0;
        for (int i = 0; i < array.length-1; i++) {
            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){
                    break;
                }
            }
        }
        return array;
    }
}

结果:

[64, 58, 54, 53, 45, 43, 2, 1]

稀疏数组

  • 需求:编写五子棋游戏中,有存盘退出和续上盘的功能。
  • 分析问题:下棋子的地方在二维数组中置1,没有子点的置0,因为该二维数组的狠多值是默认0,因此记录了很多没有意义的数据。
  • 解决:稀疏数组

稀疏数组介绍

  • 当一个数组中大部分元素为0,或者为同一值的数组时,可以使用稀疏数组来保存该数据。
  • 稀疏数组的处理方式;
    • 记录数组一共有几行几列,有多少个不同值
    • 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模

示例:

package array;

public class ArrayDemo08 {
    public static void main(String[] args) {
        //创建一个二维数组 11*11 0 没子 1黑棋 2 白棋
        int[][] array1 = new int[11][11];
        array1[1][2] = 1;
        array1[2][3] = 2;
        System.out.println("输出原始数组");
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                System.out.print(array1[i][j] + "\t");
            }
            System.out.println();
        }

        //转化为稀疏数组保存
        //获取有效值的个数
        int sum = 0;
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                if (array1[i][j] != 0) {
                    sum++;
                }
            }
        }
        System.out.println("有效值的个数:"+sum);

        //创建一个稀疏数组
        int[][] array2 = new int[sum+1][3];
        array2[0][0] = 11;
        array2[0][1] = 11;
        array2[0][2] = sum;

        //遍历二维数组 将非零的值 存入稀疏数组中
        int count = 0;
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                if (array1[i][j] != 0){
                    count++;
                    array2[count][0] = i;
                    array2[count][1] = j;
                    array2[count][2] = array1[i][j];
                }
            }
        }

        System.out.println("输出稀疏数组:");
        for (int i = 0; i < array2.length; i++) {
            for (int j = 0; j < array2[i].length; j++) {
                System.out.print(array2[i][j]+"\t");
            }
            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];
        }

        //打印还原数组
        for (int i = 0; i < array3.length; i++) {
            for (int j = 0; j < array3[i].length; j++) {
                System.out.print(array3[i][j]+"\t");
            }
            System.out.println();
        }
    }
}

结果:

输出原始数组
0	0	0	0	0	0	0	0	0	0	0	
0	0	1	0	0	0	0	0	0	0	0	
0	0	0	2	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
有效值的个数:2
输出稀疏数组:
11	11	2	
1	2	1	
2	3	2	
稀疏数组还原:
0	0	0	0	0	0	0	0	0	0	0	
0	0	1	0	0	0	0	0	0	0	0	
0	0	0	2	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	

Process finished with exit code 0

面向对象编程OOP

什么是面向对象

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

  • 面向对象编程的本质就是:以类的方式组织代码,以对象的形式组织(封装)数据。

  • 抽象

  • 三大特性:封装、继承、多态

  • 值传递和引用传递

示例:引用传递

package oop;

public class Demo05 {
    //引用传递:对象,本身还是值传递
    //对象 内存!
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);
        Demo05.change(person);
        System.out.println(person.name);
    }

    public static void change(Person person){
        person.name = "Shuang";
    }
}


class Person{
    String name;
        }

结果:

null
Shuang

示例:值传递

package oop;

public class Demo04 {
//值传递
    public static void main(String[] args) {
        int a = 1;
        System.out.println(a);
        Demo04.change(a);
        System.out.println(a);
    }

    public  static void change(int a){
        a=10;
    }
}

结果:

1
1

类与对象的关系

  • 对象---是具体的事物,类---是抽象的 是对对象的抽象,类--是对象的模板

创建与初始化对象

  • 使用new关键字创建对象

  • 使用new关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化 及 对类中构造器的调用

  • 构造方法:

    • 方法名必须跟类名相同
    • 没有返回值
  • 构造器作用

    • new 本质在调用构造方法
    • 初始化对象的值

    注意点:

    • 定义有参构造器,如果想使用无参构造器,必须显示的定义一个无参构造器

内存分析

package oop;

import oop.demo03.Pet;

public class Application {
    public static void main(String[] args) {
        Pet dog = new Pet();
        dog.name = "旺财";
        dog.age = 3;
        dog.shout();
        System.out.println(dog.name);
        System.out.println(dog.age);
        Pet cat = new Pet();
    }

}
package oop.demo03;

public class Pet {
    public String name;
    public int age;
    public void shout(){
        System.out.println("叫了一声");
    }
}

注意:左面是栈,右边是堆,堆里面有个特殊区叫方法区

简单小结类与对象

  • 类与对象

    • 类是一个模板:抽象 , 对象是一个具体的实例
  • 方法

    • 定义 调用
  • 对象的应用

    • 引用类型 + 基本类型(8个)

      对象是通过引用来操作的:栈----》堆 (地址)

  • 属性:字段Field 成员变量

    • 默认初始化: 数字 --- 0 0.0

      ​ char --- u0000

      ​ boolean --- false

      ​ 引用 --- null

    • 修饰符: 属性类型 属性名 = 属性值!

  • 对象的创建和使用

    • 必须使用new 关键字创造对象,构造器
  • 类:

    • 静态的属性 --- 属性
    • 动态的行为 --- 方法

封装

  • 该露的露,该藏的藏

    • 就是设计程序“高内聚,低耦合”

      高内聚:就是类的内部数据操作细节自己完成,不允许外部干涉

      低耦合:仅暴露少量的方法给外部使用

  • 属性私有:get/set

  • 封装好处

    • 提高代码的安全性,保护数据
    • 隐藏代码的实现细节
    • 统一接口 get/set [有时set 里面对数据进行不合法判断]
    • 增加系统可维护性

继承

  • Java中类只有单继承,没有多继承!
  • extends关键字
  • java中所有的类都继承Object类
  • 私有的 不可以继承

super this 注意点

  • super调用父类的构造方法,必须在子类方法的第一个

  • super 必须只能出现在子类的方法或者构造方法中!

  • super 和 this 不能同时调用构造方法!

  • VS this

    • this:本身调用者这个对象
    • super:代表父类对象的应用

    前提:

    ​ this:没有继承也可以使用

    ​ super: 只能在继承套件才可以使用

    构造方法:

    ​ this() : 本类的构造

    ​ super():父类的构造

重写

  • 需要有继承关系,子类重写父类的方法
  • 方法名必须相同
  • 参数列表必须相同
  • 修饰符:范围可以扩大 public > protected > default > private
  • 抛出的异常:范围,可以缩小,但不能扩大;e.g.原来是 Exception(大)可以变为 ---》 ClassNotFoundException
  • 重写:子类和父类必须要一致,方法体不同

静态方法

  • 子类父类静态方法 名与参数相同 不构成重载 [IDEA中重写方法旁 有个蓝色的小o]

示例:

package oop;

import oop.demo05.A;
import oop.demo05.B;

public class Application {

    //静态方法和非静态方法区别很大!
       //静态方法:
          // 方法的调用只跟左边,定义的数据类型有关
       //非静态方法:
          //  重写
    public static void main(String[] args) {
        A a = new A();
        a.test();
        a.test2();
        //父类的引用指向了子类
        B b = new A();//子类重写了父类的方法
        b.test();
        b.test2();
    }

}

package oop.demo05;

public class A extends B{
    @Override
    public void test() {
        System.out.println("A=>test()");
    }

    public static void test2() {
        System.out.println("A=> static test()");
    }
}

package oop.demo05;

public class B {
    public  void test(){
        System.out.println("B=>test()");
    }

    public static void test2() {
        System.out.println("B=> static test()");
    }
}

结果:

A=>test()
A=> static test()
A=>test()
B=> static test()

多态

  • 动态编译:类型,可扩展性

  • 即同一方法可以根据发送对象的不同而采用多种不同的行为方式

  • 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多[父类,有关系的类]

  • 注意事项:

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

    • 父类和子类,有联系,类型转换异常 ClassCastException 类型转换异常

    • 存在条件:继承关系,子类重写父类方法,父类引用指向子类对象

      e.g. Person s1 = new Student();

    • static final 修饰 方法不能重写 [static方法属于类 它不属于实例],private方法是私有的也不能重写

    • instanceof (类型转换) 引用类型

示例:

package oop.demo06;

public class Person {
    public void run(){
        System.out.println("run");
    }
}

package oop.demo06;

public class Student extends Person{
    @Override
    public void run() {
        System.out.println("student run");
    }

    public void eat(){
        System.out.println("Student eat");
    }
}
package oop;

import oop.demo05.A;
import oop.demo05.B;
import oop.demo06.Person;
import oop.demo06.Student;

public class Application {

    public static void main(String[] args) {
        //一个对象的实际类型是确定的
//        new Person();
//        new Student();

        //可是指向的引用类型就不确定了

        //子类能调用的方法都是自己的或者继承父类的
        //父类型 可以指向子类,但不能调用的子类独有的方法
         Student s1 = new Student();
         Person s2 = new Student();//父类的引用指向子类
         Object s3 = new Student();
         s1.run();
         s2.run(); // 子类重写了父类的run方法
        //对象能执行哪些方法,主要看对象左面的类型,和右面关系不大

       // s2.eat()//err 父类没有eat方法 eat是子类的
    }
}

结果:

student run
student run

instanceof

示例:

package oop;

import oop.demo05.A;
import oop.demo05.B;
import oop.demo06.Person;
import oop.demo06.Student;
import oop.demo06.Teacher;

public class Application {

    public static void main(String[] args) {
         // Object 》 Person  》  Student
        // Object 》 Person 》 Teacher
        // Object 》String
        //System.out.println(X instanceof Y) //能不能编译通过
        Object object = new Student();
        System.out.println(object instanceof Student);//true
        System.out.println(object instanceof Person);//true
        System.out.println(object instanceof Object);//true
        System.out.println(object instanceof Teacher);//false
        System.out.println(object instanceof String);//false
        System.out.println("----------------------");
        Person person = new Student();
        System.out.println(person instanceof Student);//true
        System.out.println(person instanceof Person);//true
        System.out.println(person instanceof Object);//true
        System.out.println(person instanceof Teacher);//false
//        System.out.println(person instanceof String); 编译报错
        System.out.println("----------------------");
        Student student = new Student();
        System.out.println(student instanceof Student);//true
        System.out.println(student instanceof Person);//true
        System.out.println(student instanceof Object);//true
//        System.out.println(student instanceof Teacher);编译报错
//        System.out.println(student instanceof String);编译报错
    }
}

结果:

true
true
true
false
false
----------------------
true
true
true
false
----------------------
true
true
true

static

  • static 不能修饰类
  • static静态代码块和包

示例:

package oop.demo07;

public class Person {
    {
        System.out.println("匿名代码块");//在构造器之前调用 赋初始值
    }

   static {
       System.out.println("静态代码块");//只执行一次
   }

   public Person(){
       System.out.println("构造方法");
   }

    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person();
    }
}

结果:

静态代码块
匿名代码块
构造方法
匿名代码块
构造方法

示例:

package oop.demo07;

import static java.lang.Math.PI;
import static java.lang.Math.random; // 用静态包

public class Test {
    public static void main(String[] args) {
        System.out.println(random()); // 直接写Math里面的方法和常量即可 不用在带上 Math
        System.out.println(PI);
    }
}

final

  • final 修饰类---不能在更改与继承、断子绝孙 hhh

抽象类

package oop.demo08;

public abstract class  Action {
    
    //约束 有人帮我们实现
    //抽象方法 只有方法的名字 没有实现
    public abstract void doSomething(); 
    
    //1、不能new这个抽象类,只能靠子类去实现它:约束!
    //2、抽象类中可以写抽象方法
    //3、抽象方法必须在抽象类中
    //4、抽象的抽象
    
    //思考? 1、 抽象类new不出来 它存在构造器吗?
    //      2、抽象类存在的意义 :抽象出来公共的东西--提高开发效率--可扩展性高
}

接口

  • 普通类:只有具体的实现
  • 抽象类:具体实现和规范(抽象方法)都有!
  • 接口:只有规范
  • 接口的关键字是interface
  • 接口的本质是契约

接口作用

  • 约束
  • 定义一些方法,让不同的人实现
  • 接口中的所有定义的方法都是public abstract
  • 接口中定义常量都是 public static final
  • 接口不能被实例化,接口中没有构造方法
  • implements可以实现多个接口
  • 必须要重写接口中的方法

内部类

  • 内部类就是在一个类的内部在定义一个类,比如A类中定义一个B类,那么B类相对A类来说就成为内部类,而A类相对于B类来说就是外部类了。
    • 成员内部类
    • 静态内部类
    • 局部内部类
    • 匿名内部类
  • lambda表达式细看内部类

demo1看一下

package oop.demo10;

public class Outer {

    private int id = 10;
    public void out(){
        System.out.println("这是外部类的方法");
    }

    private void print(){
        System.out.println("外部类私有的方法");
    }

    private void test(){
        class One{

        }
    }


   public class Inner{
        public void in(){
            System.out.println("这是内部类中的方法");
        }
        //获得外部类的私有属性和私有方法
        public void getId(){
            System.out.println(id);
            print();
        }

    }
}

package oop;

import oop.demo10.Outer;

public class Application {

    public static void main(String[] args) {
        Outer outer = new Outer();
        //通过外部类来实例内部类
        Outer.Inner inner = outer.new Inner();
        inner.getId();;

    }

}

demo2看一下

package oop.demo10;

public class Test {
    public static void main(String[] args) {
        //没有名字初始化类 不用将示实例保存到变量中
        new Apple().eat();
        new UserService(){
            @Override
            public void hello() {
                System.out.println("哈哈哈哈");
            }
        };
    }
}
class Apple{
    public void eat(){
        System.out.println("123");
    }
}

interface UserService{
    void hello();
}

异常机制

什么是异常?

  • Exception

  • 异常指程序运行中出现的不期而至的各种状况:e.g. 文件找不到,网络连接失败,非法参数等

  • 异常发生在程序运行期间,它影响了正常的程序执行流程

简单分类

三种类型异常

  • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序无法预见的。例如要打开一个不存在的文件,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常:运行时异常是可能被程序员避免得异常。与检查性异常相反,运行时异常可以在编译时别忽略。
  • 错误ERROR:错误不是异常,而是脱离程序员控制的问题,错误在代码中通常被忽略。例如当栈溢出时,一个错误就发生了,它们在编译也检查不到的

异常体系结构

  • java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类
  • 在JavaAPI中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception
Throwable ---- ERROE ---- VirtulMachineError  ...
					 ---- AWTError[GUI错误]	  ...

          ---- Exception ---- IOException      ...
						 ---- RuntimeException ...
            

Error

  • Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关
  • Java虚拟机运行错误(VirtulMachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,java虚拟机一般会选择线程终止
  • 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数时是程序运行时不允许出现的状况

Exception

  • 在Exception分支中有一个重要的子类RuntimeException(运行时异常)
    • ArrayIndexOutOfBoundsException 数组下标越界
    • NullPointerException 空指针异常
    • ArithmeticException 算术异常
    • MissingResourceException 丢失资源
    • ClassNotFoundException 找不到类 这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理
  • 这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生
  • Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下时可以被程序处理的,并且程序中应该尽可能的去处理这些异常

异常处理机制

  • 抛出异常
  • 捕获异常
  • 异常处理的五个关键字
    • try
    • catch
    • finally
    • throw
    • throws
package exception;

public class Test {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;
        try {
            new Test().a();
            System.out.println(a/b);
        }catch (Error e){//catch 捕获异常异常 !!捕获多个异常 : 小----大 要先捕获小范围异常在到大范围异常
            System.out.println("Error");
        }catch (Exception e){
            System.out.println("Exception");
        }catch (Throwable e){
            System.out.println("Throwable");
        } finally {
            System.out.println("Finally");// 无论有无异常 都会执行 一般善后
            //一般用来IO 资源 关闭!
        }
    }

    public void a(){
        b();
    }

    public void b(){
        a();
    }
    
    public void test(int a,int b) throws ArithmeticException{ //方法上抛出异常时throws
        if (b==0){ //主动抛出异常 throw throws
            throw new ArithmeticException();//一般在方法中使用
        }
    }
}

自定义异常

  • 用户自定义异常,只需要继承Exception即可
  • 在程序中使用自定义异常,大体可以分以下几个步骤
    • 创建自定义异常
    • 在方法中通过throw关键字抛出异常对象
    • 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作
    • 在出现异常方法的调用者中捕获并处理异常

示例:

package exception;

public class MyException extends Exception{

    //传递数字>10
    private int detail;

    public MyException(int detail) {
        this.detail = detail;
    }

    //toString
    @Override
    public String toString() {
        return "MyException{" +"detail=" + detail + '}';
    }
}

package exception;

public class Test3 {
    static void test(int a) throws MyException{
        System.out.println("传递的参数:"+a);
        if (a>10){
            throw new MyException(a);
        }
        System.out.println("OK");
    }

    public static void main(String[] args) {
        try {
            test(12);
        } catch (MyException e) {
            System.out.println("MyException=>"+e);
        }
    }
}

结果:

传递的参数:12
MyException=>MyException{detail=12}

实际经验的总结

  • 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
  • 在多重catch块后面,可以加一个catch(Exception大异常)来处理可能会遗漏的异常
  • 对于不确定的代码,也可以加上try-catch,处理潜在的异常
  • 尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出
  • 具体如何处理异常,要根据不同的业务需求和异常类型去决定
  • 尽量添加finally语句块去释放占用的资源 IO Scanner...

IDEA快捷键

  • ctrl + D 复制当前行到下一行
  • 100.for 回车会自动生成for语句
  • alt + insert
  • ctrl + H 继承树
  • ctrl + alt + t 选中代码 可快速生成try catch
posted @ 2020-11-15 19:36  学点东西真不容易  阅读(184)  评论(0编辑  收藏  举报