JavaSE笔记

2018-08-07  本文已影响0人  陈先森mansplain

Java的三大平台

JavaSE Java的标准平台:包含了Java的基础的功能,学习的语法,内置的API方法
JavaEE Java的企业级应用平台:JavaSE的基础上,扩展了一些API,用于B/S结构的企业应用的开发
JavaME Java的移动应用平台:JavaSE缩微版,给嵌入式系统或移动端系统使用过时

Java语言特点

1.跨平台   平台-操作系统
任何平台上编写的Java程序,可以在另外的平台上执行

JDK Java的开发环境
JRE Java的运行环境 - Java虚拟机
java文件 ->(编译) class文件 -> Java虚拟机中运行

2.面向对象: 以人类正常思维开发和设计软件,开发程序开发方法:支撑大型的关系复杂系统的构建

3.多线程:支持多任务场景

4.分布式:支持网络应用  

5.简单:比C++简单 指针,回收(内存泄露)Java中没有指针, 系统自动回收
public class Demo1 {类块 ,类中的代码都要写在类块之中
    
    public class Java中的关键字
    
        主程序(main方法) :一个Java程序需要执行,必须有一个main方法
        mian方法是程序的入口,需要程序执行的代码,一定要经过main方法
        public static void main(String[] args) {方法块
            System.out.println("中文");
            Java程序之后的输出语句
            System.out.println(123);
            
             写完一行代码后,编译区出现红叉(报错) ,表示代码的写法已经
             违反了Java的语法规则 
            
            System.out.println(123);
            System.out.print("中文");不换行输出
            
            
}
变量:用于存储程序在计算过程中用到数据
public class Demo1 {
    错误演示,不能存在相同的变量名
    int a=5;
    int a=4;

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        在Java中规定,变量需要先声明 (int a)
        并且对变量进行初始化(对变量设置初始值),之后才可以正确使用
        
        声明了一个变量 a , 变量a的值是5
        int a=5;
        int a=6; 错误演示,不能同时存在相同的变量名
        
        使用输出语句打印一个变量时,实际的输出内容是变量所指代数据值
        System.out.println(a);结果是5
        
        变量所指代的数据值可以改变,也就是可以对变量进行重新赋值
        a=6;
        
        System.out.println(a); 结果是6
       
        
         变量只需要声明一次即可在一个块内(方法块,类块)
         不能同时出现多个相同名字的变量
         
       
    变量的命名:
    可以由字母,数字,”_”和“$”组成。
    不能以数字开头,区分大小写,不能使用java的关键字和保留字
    可以使用中文命名但不建议使用。
     
      1.见名知意  
            int age=12; 
            int month=12;
      2.驼峰命名法:如何变量名由多个英文单词组成
                从第二个单词开始 每个单词首字母大写
          int className=12;
        
       int 年龄=5;//中文可以作为变量名,但是不建议使用
       
       System.out.println(123456879*987654321);
       int num1=123456879;
       int num2=987654321;
       System.out.println(num1*num2);
       
       int class=5; Java中的关键字和保留字不能作为变量名
       int class=2; 错误演示
    }

}
数据类型

  基本数据类型

  整型
    byte   占1个字节(一个字节占8位)-128-127

    short  占2个字节                -2^15 - (2^15-1)

    int    占4个字节                -2^31 - (2^31-1)

    long   占8个字节                -2^63 - (2^63-1)

  浮点型

    float  占4个字节 单精度

    double 占8个字节 双精度

  字符型

    char

  布尔型

    boolean
public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        byte b=127; 声明byte类型变量 b 值为127
        
        short s=255; 声明short类型变量 s 值为255
        
        int i=1000; 声明int类型变量 i 值为1000
        
        在Java程序中直接书写的整数值 (整数直接量),默认为int类型
         
        如果需要声明数据为long类型,在数据的末尾加上 L/l
        long l=154L;
        
        double数据类型比float数据;类型更加精确
        float f=5.2F; 单精度
        
        double d=5.2; 双精度
        
        值写在' ' 中,只能有一个字符
        char c='中';
        
        System.out.println(c+1);
        
        boolean b1=true;
        
        boolean b2=false;
        
    }
基本数据类型转换

   1.隐式转换(自动转换)

      小的数据类型可以自动转换到大的数据类型

   2.强制转换

      大的数据类型转换到小的数据类型

      目标数据类型 变量名=(目标数据类型) 需要转换的变量或者值;

       int i=5;
       byte b=(byte) i;
数据类型转换.png
在Java程序中直接书写的整数值 (整数直接量),默认为int类型
Java允许将整数直接量赋值给 byte ,short,char,不超出数据类型的取值范围即可
        byte b=20;
        System.out.println(b); 结果20
        char c=25;
        short s=22;
        
        变量b是byte类型属于隐式转换,Java自动执行
        int i=b;
        System.out.println(i); 输出结果20
        
     
         * 由于i1是int类型 ,将i1赋值给byte类型的变量 b1
         * 属于 将大的数据类型转为小的的数据 Java中不允许直接操作
         * 所有会出现编译报错,因为变量i1 不是整数直接量
           byte b1=5; 
           int i1=12;
           b1=i1;*/
        
    
           byte ,short,char在参与运算时,会先转换为int
                   

          byte bt1=10;
          bt1=bt1+5;  int - > byte 大的数据类型转为小的数据类型, 编译报错
强制转换
        int i=5;
        byte b=(byte)i;
        System.out.println(b);
        
        double d=10;
        System.out.println(d);
        
        //进行强制转换,可能造成数据精度的缺失
        int i1=(int)5.9;
        System.out.println(i1);
        
        
        System.out.println(1-0.1);
public static void main(String[] args) {
        // TODO Auto-generated method stub
        int a=5;
        System.out.println(a);
        a=10;
        System.out.println(a);
        
        
         * 声明int类型变量i1,无初始化
         * 声明int类型变量i2,初始值10
         * 所以,直接使用变量i1会编译报错
         
        int i1,i2=10;
        System.out.println(i1); 会出现编译报错
        System.out.println(i2);
    }
Java中的运算符
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println(12*25);
        Java中变量也可以进行运算
        int n=9;
        int m=2;
        System.out.println(n+m);//11
        System.out.println(n-m);//7
        System.out.println(n*m);//18
        如果参与除法运算的变量都是int类型,则其结果也是hint
        System.out.println(n/m);//4
        
        如果参与除法运算的两个变量类型不一致
        其结果以大的数据类型为准
        int a=3;
        double b=9;
        System.out.println(b/a);//3.0
        
        求余结果的正负 取决于第一个数的正负
        System.out.println(5%2);//1
        System.out.println(5%-2);//1
        System.out.println(-5%2);//-1
        System.out.println(-5%-2);//-1
    }
public static void main(String[] args) {
        // TODO Auto-generated method stub
         ++ ,-- 自增,自减运算符
        
        
         * 如果 int i=5; ++i 表示 在i初始值的基础上+1
         * ++i 相当于 i=i+1;
         
        int i=5;
        System.out.println(i);//5
        ++i;
        System.out.println(i);//6
        
        int n=2;
        int m=3;
        
        
         *   前置 ++ :
         *    int n=2; 如果使用++n (在输出语句中,在运算表达式中都表示使用)
         *    这种情况下,++n的值为 初始值+1
         
        
          System.out.println((++n)+(++m));//7
          System.out.println(n);//3
          System.out.println(m);//4
            
        
        
         * 后置 ++ :
         *  如果使用n++(在输出语句中,在运算表达式中都表示使用)
         *  这种情况下,n++的值为 n的原始值 ,但是之后再使用n时,n的值是+1后的结果
         
        System.out.println(n++);//2
        System.out.println(n+1);//4
    }
+=的特殊情况
public static void main(String[] args) {
        // TODO Auto-generated method stub
        int n=2;
        n+=5; 表示 n=n+5;
        System.out.println(n);
        
        int m=10;
        m%=4;m=m%4;
        System.out.println(m);
        
        byte b=2; b=b+1; 会编译报错
        b+=1;该情况不会出现编译报错 ,Java自动执行了强制转换
    }
比较运算符
public static void main(String[] args) {
        // TODO Auto-generated method stub
      比较运算符:比较两个数值或者变量之间的大小关系
      int n=5;
      int m=4;
      int k=4;
      
      逻辑表达式:比较两个或者多个变量之间的关系算式
      逻辑表达式的结果为boolean - true(成立) , false(不成立) 
      System.out.println(n>m);//true
      System.out.println(n<m);//fasle
      System.out.println(n>=m);//true
      System.out.println(n<=m);//false
      System.out.println(n!=m);//true
      System.out.println(n==m);//fasle
      System.out.println(m==k);//true
    }
逻辑运算符
public static void main(String[] args) {
        // TODO Auto-generated method stub
        逻辑运算符
        
         逻辑与  &&
         &&左右两边的表达式同时成立,整个表达式才成立
        int a=5;
        int b=10;
        System.out.println(a<b&&b>12);//false
        System.out.println(a<b&&b>5);//true
        
        逻辑或 ||
        ||左右两边的表达式,只要有一端成立,整个表达式就成立
        如果||两端的表达式都不成立。则整个表达式不成立
        int a1=12;
        int b1=20;
        System.out.println(a1<=20||b1>100);//true
        System.out.println(a1>=20||b1>100);//false
        
        逻辑非 !
        对逻辑表达式的结果取相反的结果
        
        System.out.println(a1>b1);//fasle
        System.out.println(!(a1>b1));//true
        
        System.out.println(!true);//fasle
    }
短路问题
 * 对于&&来说,如果左边的条件表达式结果明确为fasle
 * java编译器则不会再执行&&右边的条件表达式代码

 * 对于||来说,如果左边的条件表达式结果明确为true
 * java编译器则不会再执行||右边的条件表达式代码

        int a=10;
        int b=15;
        System.out.println(++a<10&&++b>10);//false
        System.out.println(a);//11
        System.out.println(b);结果15 由于&&短路问题 ++b没有被执行 ,结果仍是15
字符串拼接
public static void main(String[] args) {
        // TODO Auto-generated method stub
        引用数据类型
        String 字符串  String str="hello";
        String str="hello1";
        System.out.println(str);
        
         * 当+(加号)的左边或者右边出现字符串时(String ,"")
         * 则加号不再是加法运算的功能,而是字符串拼接功能
        
        int n=10;
        int m=5;
        System.out.println("n="+n);此时加号将双引号的内容与变量n的值拼接在一起
        
        System.out.println("n="+n+", m="+m);
        
        int age=12;
        int month=12;
        System.out.println("年龄:"+age);
        System.out.println("月份:"+month);
    }
三元运算符
public static void main(String[] args) {
        // TODO Auto-generated method stub
          三元运算符   
        
         *  公式: 条件表方式?表达式1:表达式2;
         *  如果条件表方式的值为true  则返回表达式1的结果
         *  如果条件表方式的值为false 则返回表达式2的结果
         
        int a=1;
        int b=2;
        System.out.println(5==2?a+b:a-b);
    }
流程控制语句
 * 语法: 
         *  if(条件表达式){//if语句块
         *     语句块内容的代码(不固定)
         *  }
         *  
         *  如果条件表达式的结果为true, 则执行语句块内的代码
         *  如果条件表达式的结果为false,则不执行语句块内的代码
         * if(条件表达式){
         * 
         * }else{
         * 
         * }
         * 如果if中的条件表达式结果为true, 则执行if语句块的代码
         * 如果if中的条件表达式结果为false,则执行else语句块的代码

        int m=1;
        if(m>=2){
            System.out.println("1>=2");
        }else{
            System.out.println("1<2");
        }
         * if-else if
         * 语法结构不固定,可以写多个else if条件
         * 其中每一个if语句块都是独立,只会执行其中一个
         * 如果存在多个条件成立的if语句块
         * 则执行第一个成立的if语句块

        int m=5;
        
        if(m>8){
            System.out.println("a");
        }else if(m>4){
            System.out.println("b");
        }else if(m>1){
            System.out.println("c");
        }
         * switch(num){括号中的内容是整型数值
         *    case 1:
         *    执行的代码;
         *    
         *    case 2:
         *    ...
         *    break; 保证每个case语句独立执行
         *    
         *    default:如果所有case都不符合条件,则执行default

        int num=5;
        switch(num){
        case 2:
            System.out.println("b");
            break;
        case 3:
            System.out.println("c");
            break;
        case 1:
            System.out.println("a");
            break;
        case 4:
            System.out.println("d");
            break;
        default:
            System.out.println(num);
        }
switch中可以使用的数据类型
switch()中可以使用那些数据类型
    int ,byte ,short,char可以
    long 不可以

JDK1.7开始 switch中可以使用字符串作为参数(指的的switch括号中的内容)
         * while(条件表达式){
         *   执行的代码
         * }
         * 
         * 首先判断条件表达式结果,如果为true
         * 则执行while语句块中的代码,代码执行之后
         * 再一次判断条件表达式的结果是否为true
         * 如果为true ,则继续执行代码
         * 直到条件为false的时候,结束循环

        int m=10;
        while(m>1){
            if(m%2==0){
                System.out.println("m="+m);
            }
            m--;
        }
do-while:先执行一次代码,再进行判断
        int n=1;
        do{
            System.out.println("n="+n);
            n++;
        }while(n<=10);
         * for(循环变量的初始化;循环条件;循环变量的改变){
         *    执行的代码
         * }
         * 执行顺序:
         *  1.循环变量的初始化
         *  2.循环条件
         *  3.执行的代码
         *  4.循环变量的改变
         *  5.循环条件
         *  如果条件为true,重复以上操作
         *  如果条件为false,结束for循环

        for(int i=1;i<=10;i++){
            System.out.println(i);
        }
循环嵌套:应用单层for循环的执行过程,依次执行
        for(int i=1;i<=5;i++){
            for(int j=1;j<=5;j++){
                System.out.println("i="+i+" j="+j);
            }
        }
* 中断循环
         * break:如果在循环结构中执行了break,
         *       则整个循环停止,继续执行循环外的代码
         * 
         * continue:如果在循环结构中执行了continue,
         *          会跳过当前循环,执行下一次循环

        for(int i=1;i<=10;i++){
            if(i==5){
                break;
            }
            System.out.println("当前i="+i);
            
        }
        
        System.out.println("华丽的分割线--------------");
        
        for(int j=1;j<=10;j++){
            if(j==5){
                continue;如果执行力continue,则它之后代码不会执行
                         直接进行下一次循环
            }
            System.out.println("当前j="+j);
            
        }
变量作用域问题

变量只在声明时它所在的块内有效

        int n=2;
        if(n>1){
          int m=5;
          System.out.println(m);
        }
        System.out.println(m); 会出现编译报错,无法使用变量m
数组
数组:用于存储一组相同数据类型的容器

* 数组中的数据叫做元素,每一个元素都有一个对应的下标
* 第一个元素,下标为0,依次递增
* 数组中元素的个数,表示数组的长度
创建数组的方式
创建数组  声明一个int类型的数组arr 长度是5
int[] arr=new int[5];
        
声明一个int类型的数组arr1 ,数组中的元素分别是1,2,3
int[] arr1=new int[]{1,2,3};

int [] arr2={1,2,3};

要求如果声明了具体的长度就不能声明具体的元素
如果声明了具体的元素就不能声明具体的长度
int[] arr2=new int[5]{1,2,3,4,5}; 编译报错

会出现编译报错,数组只能存放相同数据类型的元素
int[] arr3=new int[]{2.1,5,3}; 
不同数据类型数组的默认值
int[],byte[],short[],long[]中元素默认值是0
char[] 元素默认值是空字符
double[],float[]元素默认值0.0
boolean []元素默认值false
操作数组中的元素
        int[] arr=new int[]{4,5,7,3,1};
        
        int num=arr[2];获取元素值
        System.out.println(num);
        
        arr[0]=9;对元素赋值 
        System.out.println(arr[0]);
        
        数组的长度属性 length, arr.length
        System.out.println(arr.length);
        
        arr.length=20; 只读属性,不能重新赋值,会编译报错
遍历数组:将数组的每一个元素获取出来
int[] arr=new int[]{5,4,6,1,2};
for(int i=0;i<arr.length;i++){
    System.out.println(arr[i]);
}

在编码时,如果使用了数组中不存在的下标,并不会出现编译报错
但是在程序执行时,会出现数组下标越界的异常
System.out.println(arr[5]);
java.lang.ArrayIndexOutOfBoundsException

二维数组:数组中每一个元素还是一个数组
int[][] arr1=new int[2][3];

int[][] arr=new int[][]{{4,5},{9,2,3}};

System.out.println(arr.length);外层数组的长度
System.out.println(arr[0].length);内层小数组长度
System.out.println(arr[1].length);内层小数组长度

该声明方式不会编译报错,但运行程序则出现空指针异常
int[][] arr2=new int[2][];

java.lang.NullPointerException 空指针异常
由于内层数组并不存在,arr2[0],arr2[1] 的值为null
使用null掉用数组的属性,会报出空指针异常

操作二维数组元素
int[][] arr=new int[][]{{4,5},{9,2,3}};
System.out.println(arr[0][0]);
System.out.println(arr[1][2]);
...
遍历二维数组
for(int i=0;i<arr2.length;i++){
    for(int j=0;j<arr2[i].length;j++){
        System.out.println(arr2[i][j]);
    }
}
冒泡排序

每一轮相邻的两个数之间进行两两比较,如果前一个数比后一个数大
则交换位置,一轮之后则找出最大值。之后其余的数据进行新一轮的
两两比较找出最大值,直到没有相邻的两个数再需要比较。

         * 冒泡排序: 9,3,8,2,7,1
         *  第一轮 :3,8,2,7,1,9  5次
         *  第二轮: 3,2,7,1,8   4次
         *  第三轮: 2,3,1,7    3次
         *  第四轮: 2,1,3     2次
         *  第五轮: 1,2       1次
for(int i=1;i<arr.length;i++){表示需要比较多少轮
    for(int j=0;j<arr.length-i;j++){表示每轮需要比较多少次
        if(arr[j]>arr[j+1]){如果前一个元素大于后一个 互换位置
            int temp=arr[j];
            arr[j]=arr[j+1];
            arr[j+1]=temp;
        }
    }
}
快速排序
int []arr=new int[]{9,3,8,2,7,1};
快速排序方法 只能按照升序排列
Arrays.sort(arr);

1和5表示下标范围,可以修改。
Arrays.sort(arr,1,5);
数组的复制
        int[] arrOld=new int[]{5,9,4,5,4,8};
        int[] arrNew=new int[6];//0 0 9 4 5 0
         * 数组的复制
         * 第一个参数:源数组(被复制的数组)
         * 第二个参数:从源数组的第几个下标开始复制元素
         * 第三个参数:目标数组(接收复制元素的新数组)
         * 第四个参数:从目标数组的第几个下标开始放置元素
         * 第五个参数:从源数组中复制几个元素
         
        System.arraycopy(arrOld, 1, arrNew, 2, 3);
        int[] arrOld=new int[]{5,9,4,5,4,8};
    
         * 该方法会创建一个新数组
         * 第一个参数:源数组
         * 第二个参数:新数组的长度
        
        int[] arrNew=Arrays.copyOf(arrOld,6);
内存空间
内存图.png
方法的定义
* 方法:用于解决一段具有特定功能的代码
         * 
         * 方法的定义:
         * [修饰词] 返回值类型  方法名([参数类型 参数名]){ 方法体 } 
         * 
         * 修饰词 :public ,static等关键字组成 表示该方法的使用(访问)的权限
         * 
         * 返回值类型:
         *    如果方法中的代码经过计算后会得到一个结果
         *    那么该结果的数据类型 就是方法的返回值类型
         *    需要使用关键字 return 返回该结果
         *    
         *    如何方法中的代码,没有结果值(输出语句不算结果值)
         *    则方法的返回值类型是 void 关键字
         *    
         *    方法是先声明,再实现内容功能代码
         *    所以,方法内部有没有结果值,应该取决于是否定义返回值类型
         *    
         * 方法名:就是方法的被执行(被调用)的标识
         * 
         * 参数:参数表示方法中需要的某些不确定的数据
         *     数据类型 ,变量名
         *     参数的个数不固定,可以没有,也可以存在多个
         *     根据方法的具体需求来定
         *     
         * 方法体:表示该方法核心功能的代码

方法和方法之间是同级关系,不能在方法中定义方法
如果方法想要被执行,则需要在main方法中调用该方法
程序中方法之间可以相互调用,但不建议调用main方法

无返回值无参数类型
public static void sayHi(){
    System.out.println(1);
}
调用无返回值无参数类型方法
public static void main(String[] args) {
    sayHi();
}
    定义具有返回值类型的方法
    如果定义的方法具有明确的返回值类型
    则方法的内部必须返回一个对应的结果

    public static int test1(){
        return 2;
    }
    
    public static double test2(){
        return 1.0;
    }
    
    public static boolean test3(){
        return false;
    }
调用方式
public static void main(String[] args) {
    调用有返回值的方法
    存在返回值的方法,可以当做一个值使用
    System.out.println(test1()); - -2

    short a=(short)test1();
    System.out.println(a); - -2
}

如果在方法中出现return ,表示方法的结束,不再向下执行代码。

    定义具有参数的方法
    参数根据方法的功能来设定
    求数值5 加上一个未知数的和

    public static void test4(int a){
        System.out.println(5+a);
    }
    
    public static void test5(int a,int b){
        System.out.println(a+b);
    }
    
    public static int test6(int n){
        如果在方法中出现return
        表示方法的结束,不再向下执行代码
        return n+5; 
    }
调用方式
调用有参数的方法,需要传入与参数类型对应的数据
public static void main(String[] args) {
        test4(5);
        
        test5(10,2);
        
        System.out.println(test6(55));
}

方法调用的过程:实际就是将实参传递给形参的过程

public static void main(String[] args) {
        // TODO Auto-generated method stub
       sum(1,2);实参
       int a=1;
       int b=2;
       sum(a,b);实参
}

public static int sum(int a,int b){形参
    return a+b;
}
方法定义练习
求1—100之间的整数和 
    public static int test1(){
        int sum=0;
        for(int i=1;i<=100;i++){
            sum+=i;
        }
        return sum;
    }
    
    
    求1—100之间能被3整除的数有多少个  
    public static int test2(){
        int count=0;
        for(int i=1;i<=100;i++){
            if(i%3==0){
                count++;
            }
        }
        
        return count;
    }
    
    
    求两个整数区间内的所有整数和
    public static int test3(int a,int b){
        int sum=0;
        if(a==b){
            sum=a;
        }else if(a<b){
            for(int i=a;i<=b;i++){
                sum+=i;
            }
        }else{
            for(int i=b;i<=a;i++){
                sum+=i;
            }
        }
        
        return sum;
    }
            
    随机输入不相同的三个整数 比较出其中的最大值
    public static int test4(int a,int b,int c){
        
        int max=0;
        
        if(a>b&&b>c){
            max=a;
        }else if(a>c&&c>b){
            max=a;
        }else if(b>a&&a>c){
            max=b;
        }else if(b>c&&c>a){
            max=b;
        }else{
            max=c;
        }
        
        return max;
    }
            
    求两个整数之间存在多少个奇数
    public static int test5(int a,int b){
        int count=0;
        
        if(a>b){
            for(int i=b;i<=a;i++){
                if(i%2!=0){
                    count++;
                }
            }
        }else{
            for(int i=a;i<=b;i++){
                if(i%2!=0){
                    count++;
                }
            }
        }
        return count;
    }
    
            
    随机输入一个年份 判断是否为闰年
    public static void test6(int year){
        if(year%4==0&&year%100!=0||year%400==0){
            System.out.println("闰年");
        }else{
            System.out.println("不是闰年");
        }
    }
            
    有5位学员参加了Java知识竞赛的决赛,输出决赛的平均成绩 
    public static double test7(int[] scores){
        double avg=0;//平均值
        double sum=0;//总和
        for(int i=0;i<scores.length;i++){
            sum+=scores[i];
        }
        avg=sum/scores.length;
        return avg;
    }
    
    
    求一个整数的阶乘
    public static int test8(int n){
        int num=1;
        for(int i=n;i>0;i--){
            num*=i;
        }
        return num;
    }
    
    计算数列 升序后的排列结果 
    public static void test9(int[] arr){
        Arrays.sort(arr);
        for(int i=0;i<arr.length;i++){
            System.out.println(arr[i]);
        }
    }
方法的重载

在同一个类中,允许存在多个相同名字的方法

重载的规则:
方法名相同
参数不同:个数不同或者类型不同
返回值类型可以相同,也可以不同

面向对象

类:Java中一种特殊的数据类型 - -引用数据类型

类:是一组具有相同特征和行为的事物的抽象

对象:类的一个具体的实例

类可以衍生出不同的对象,每个对象都有着类中共同的特征和行为

类的定义
public class Person {

    特征在类中叫做属性 (与之前学的变量相同)
    String name;//名字
    
    int age;//年龄
    
    double height;//身高
    
    double weight;//体重
    
    构造器(构造方法)   
    
     * 编写一个类,一定要含有一个构造器
     * 如果编写的类中,没有任何形式的构造器
     * Java编译器则会提供一个默认构造器
     * 
     * 如果类中已经存在了一种形式的构造器
     * 则编译器不再提供默认构造器
     
    public Person(){无参构造器/默认默认构造器
        
    }
    
    构造器的重载
    提供有参构造器 在创建对象时,可以直接对属性赋值
    对属性进行初始化操作
    public Person(int age1){有参构造器
        age=age1;
    }
    
    行为在类中叫做方法
    
    public void eat(){
        System.out.println("吃饭...");
    }
    
    public void sleep(){
        System.out.println("睡觉...");
    }
    
}
调用类中的属性和方法
        创建类的对象  类名 对象名(与变量名同理) = new 构造器;
        Person p1=new Person();
        通过对象.属性 和 对象.方法 进行调用.
        类中的属性具有默认值
        System.out.println(p1.name);
        
        p1.eat();
不同的对象之间不会相互影响
        Person p1=new Person();
        System.out.println("p1:"+p1.age);
        System.out.println("p1:"+p1.name);
        
        Person p2=new Person();
        System.out.println("p2:"+p2.age);
        System.out.println("p2:"+p2.name);

创建对象时,构造器的形式必须是在类中已经存在
否则无法使用,会出现编译报错

this:表示当前类的对象
     * 使用有参构造器对属性赋值
     * 如果参数名与属性名相同时
     * 提供this进行区分
     * 
     * this:表示当前类的对象

    public Student(int age){
        this();表示当前类的无参构造器
        this.age=age;
        System.out.println("有参构造器");
    }
内存空间

栈:存取速度比堆快,效率高。
栈内保存基本数据类型的局部变量和对象的引用

堆:保存对空间要求大的内容,如对象的属性,数组的元素


内层图.png
Java中的变量类型

局部变量:声明在方法中的变量或者方法中的参数

实例变量:类中的属性,又叫全局变量。

静态变量:类中static修饰的属性,又叫类变量

匿名对象 :如果对一个对象只需要进行一次方法的调用

new Person();
垃圾回收机制

Java中的垃圾回收机制是自动的,垃圾回收机制实际上是JVM内部一个优先级比较低的后台线程,垃圾回收机制仅作用于堆,与栈无关

产生垃圾的情况
变量的作用域

类变量:在类被加载时创建,只要类存在,静态变量就存在。

实例变量:在类的整个生命周期都有效

局部变量:只在方法的调用过程中有效,方法调用结束后失效

面向对象- - 继承 (子类 extends 父类)

Java中一个类可以继承另一个类,被继承的类 称为父类,另外一个称为子类
子类继承父类之后,可以使用父类的属性和方法
但是父类不能使用子类的属性和方法

继承的优点

有利于程序的扩展, 增强了代码的复用

继承的特性

单一性继承 ,一个子类只能有一个父类,但一个父类可以有多个子类

子类实例化过程
super关键字

作用:调用父类构造器 super( );
super( )括号中参数列表的形式,决定调用父类那个形式的构造器
只能出现在子类构造器中,且必须在第一行

面向对象 - - 封装

封装: 对类中的属性和方法规定访问权限,保护类中数据的安全
将类中的信息(属性和方法)隐藏起来,不允许外部程序直接访问,
而是通过该类 提供的方法进行访问

访问权限:用来控制类的成员和类的使用范围

访问权限可以修饰属性和方法 ,其中public 和 默认 可以修饰类

权限.gif
面向对象 - - 多态

多态的体现:子类和父类之间,不同的子类之间对于同一行为,有不同的实现方式

方法的重写

对从父类中继承的方法进行重新改造

方法重写的规则

重写方法被调用时,看对象类型。子类对象的重写方法被调用时,引用类型无论是父类还是子类,运行的都是子类重写后的版本。

重写和重载的区别

重写:遵循“运行期”的绑定,根据对象类型进行调用
重载:遵循“编译器”的绑定,根据参数列表不同进行调用

多态的体现:引用数据类型的转换
上溯造型(向上造型):父类的引用指向子类的对象

优点:有利于程序的维护和扩展。

static关键字

static可以修饰属性,方法和代码块,但是不能修饰局部变量

静态变量- static修饰的变量

该变量也称为类变量,被该类的所有对象共享,在类被加载时创建
只要类存在,静态变量就存在
访问方式:类名.属性名 或者 对象.属性名

静态方法 - -static修饰的方法

不需要实例化对象,可以直接访问
访问方式:类名.方法名 或 对象.方法名

静态方法的注意事项

静态块 - - static修饰的代码块

当前类被加载时,静态代码块被执行,且只被执行一次
通常用来对属性进行初始化,加载静态资源

单例模式:保证一个仅有一个实例

单例编写模式

final关键字

final修饰的类不能被继承
final修饰的方法不能被重写
final修饰的变量不能被重新赋值

如果声明属性时使用fianl修饰,属性不再有默认值

常量 :所有对象共享,不需要经常修改的数据 - static final

Java的异常处理机制

Java程序在编译或运行期间,发生的不可预期的意外,造成程序不能继续执行的情况
Java中的异常是被管理起来的,当程序发生异常,会创建出一个异常的对象

Throwable 所有异常的父类

Error 错误:天灾 人力不可抗拒 计算机硬件的问题,比如:硬盘坏了,内存掉电

Exception 异常: 人祸 主要是因为程序开发者不严谨造成的问题,可以通过代码来修补和解决

检查性异常
非检查异常
异常捕获机制
 try{
      可能发生异常的代码
 }catch(Exception e){
      发生异常则执行此处代码
 }finally{
      无论如何都会执行
}

throws 表示某个方法向上抛出异常

throw 人工制造异常

Object类:Java中所有类的父类

创建一个自定义类, 类的对象会调用出一些
类中不存在的方法,这些方法的都是继承于Object类

Object类中的方法

equals(Object obj) -boolean
比较两个对象是否为同一个对象(实际比较对象的地址是否相同)

Person p=new Person(12,"jack");
Person p1=new Person(12,"jack");
System.out.println(p.equals(p1)); - -false
== 和equals 的区别

== :比较基本数据类型的变量时,比较的是变量的值是否相同
比较引用数据类型时,比较的两个对象的地址是否相同

equals():Obejct类中的方法,默认比较的是两个对象的地址是否相同
一般Object的子类会重写该方法,从而比较的的是内容是否相同

在Person类中重写equals( )
重写equals() 从而比较两个对象之间的内容是否相同
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
测试类

Person p=new Person(12,"jack");
Person p1=new Person(12,"jack");
System.out.println(p.equals(p1)); - -true
hashCode() 返回对象的哈希值(int)

如果两个对象的equals()比较为true,则两个对象的hashCode值相同

如果两个对象的equals()比较为false 那么两个对象的hashCode值可能相同,也可能不同

toString( ) 返回对象的字符串表现形式

直接使用输出语句打印一个对象 会得到该对象地址的字符串表现显示
子类重写Object中的方法,直接输出的对象 会得到对象的属性信息

@Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }
包装类
//包装类和基本数据类型之间可以直接转换
        Integer m=20;
        
        Integer k=n;
        
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MIN_VALUE);
        
        //Integer.parseInt(String s) -int   
        //将字符串转为int 方法中的字符串必须是纯数字形式的
        //否则会出现转换异常 java.lang.NumberFormatException
        String number="12";
        System.out.println(number+1);//121
        int a=Integer.parseInt(number);
        System.out.println(a+1);//13
        
        
        //Integer.valueOf(String s) - Integer
        String num1="12";
        Integer numi=Integer.valueOf(num1);
        System.out.println(numi);
        
        
        //Integer.toString(int i) -String
        String str=Integer.toString(5);
        System.out.println(str+1);
Math类
//Math类中的属性和方法
        
        System.out.println(Math.PI);
        
        //绝对值方法  Math.abs(int i) -int  
        System.out.println(Math.abs(-20));
        
        //求立方根方法  Math.cbrt(double d) - double
        System.out.println(Math.cbrt(8));
        
        //向上取整 ,返回大于或等于参数的最小整数  Math.ceil(double d) -double 
        System.out.println(Math.ceil(-0.0));
        
        //向下取整 ,返回小于或等于参数的最大整数 Math.floor(double d) -double
        System.out.println(Math.floor(0.9));
        
        //返回两个数的最大值  Math.max(int a, int b) -int 
        System.out.println(Math.max(5, 8));
        
        //返回两个数的最小值  Math.min(int a, int b) -int 
        System.out.println(Math.min(10, 8));
        
        //返回[0.0,1.0)之间的随机小数  Math.random() - double
        System.out.println(Math.random());
        
        //四舍五入  Math.round(double d) - long 
        System.out.println(Math.round(5.0));
        
        //求平方根方法   Math.sqrt(double d) -double
        System.out.println(Math.sqrt(25));
        
        System.out.println(Math.random()*10+5);
        
        Random ran=new Random();
        int d=ran.nextInt(1000);//[0,1000)
        System.out.println(d);
Date类
Date date =new Date( ); 格林威治时间的当前系统时间
SimpleDateFormat 日期格式转换
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日  hh:mm:ss:SS");
        Date date=new Date(); 
        System.out.println(date);//Mon Aug 20 16:42:32 CST 2018
        
        --format(Date d) -String 将日期类型的数据转换成字符串形式
        String time1= sdf.format(date);
        System.out.println(time1);
日历类
        Calendar cal=Calendar.getInstance();
        
        System.out.println(Calendar.YEAR);
        System.out.println(cal.get(Calendar.YEAR));
        
        System.out.println(cal.get(Calendar.MONTH)+1);//月份比实际值少1
        
        System.out.println(cal.get(Calendar.DATE));
        
        System.out.println(cal.get(Calendar.HOUR));
        
        System.out.println(cal.get(Calendar.MINUTE));
        
        System.out.println(cal.get(Calendar.SECOND));
        
String类

字符串的定义

        String str="abc";
        String str1="";//空字符串
        System.out.println(str1);
        
        String str2=new String();//空字符串
        System.out.println(str2);
        
        String str3=new String("hello");
        System.out.println(str3);

字符串的方法

        字符串也存在下标 ,第一个字符下标为0
        String str="Tinking in Java";
        
        charAt(int index) -char 根据参数下标返回对应的字符
        System.out.println(str.charAt(7));
        
        length() -int 获取字符串长度
        System.out.println(str.length());
        
        concat(String s) -String 将参数字符串连接到原字符串的末尾 
        得到一个新的字符串 对原字符串的内容没有影响
        System.out.println(str.concat(" hello"));
        
        
         * Tinking in Java  
         * 子串:in,ava
         
        
        endsWith(String s) -boolean 判断当前字符串是否以参数(子串)为后缀
        System.out.println(str.endsWith("Java"));
        
        //equals(Object obj) - boolean 判断字符串与参数内容是否相同
        System.out.println(str.equals("abc"));
        
        
        indexOf(String s) -int 返回参数字符串在原字符串中第一次出现的位置
        位置以参数字符串中第一个字符为准
        如果不存在参数字符串 则返回 -1
        System.out.println(str.indexOf("in"));
        
        System.out.println(str.indexOf("abc"));
        
        indexOf(String s, int i) - int 
        从指定下标开始查找,参数字符串在原字符串中第一次出现的位置
        System.out.println(str.indexOf("in", 2));
        
        lastIndexOf(String s) -int 返回参数字符串在原字符串中最后一次出现的位置
        System.out.println(str.lastIndexOf("in"));
        
        isEmpty() -boolean 判断当前字符串是否为空字符串(长度为0) 是 -true , 不是 -false
        System.out.println(str.isEmpty());
        
        replace(String old, String new) - String
        将原字符串中old部分 替换 new 得到一个新字符串 
        System.out.println(str.replace("in", "***"));
        
        contains(String s) -boolean 判断参数是否为原字符串的子串
        System.out.println(str.contains("Jaa"));
        
        startsWith(String str) - boolean 判断原字符串是否以参数字符串为前缀
        System.out.println(str.startsWith("in"));
        
        
        substring(int index) -String 从给定下标的位置开始截取原字符串 得到一个新的子串
        System.out.println(str.substring(1));
        
        substring(int begin, int end) -String 从给定下标的范围截取原字符串 得到一个新的子串
        System.out.println(str.substring(1, 5));
        
        toCharArray() - char[] 将字符串转换为字符数组
        String类的内部是由一个final修饰的char[]维护的
        char[] ch=str.toCharArray();
        
        toLowerCase() -String 将原字符串中的字母转换为全小写
        System.out.println(str.toLowerCase());
        
        toLowerCase() -String 将原字符串中的字母转换为全大写
        System.out.println(str.toUpperCase());
        
        String str1=" hello world    ";
        String str2="hello world";
        System.out.println(str1.equals(str2));
        
        System.out.println(str1);
        
        trim() -String 将原字符串两端的空白字符消除掉
        System.out.println(str1.trim());
字符串内存
字符串内存.png

如果字符串中包含了字符串对象 则该内容的地址在堆中

StringBuffer和StringBuilder

StringBuffer类没有重写Object类中的equals()
所以使用equals()比较两个StringBuffer对象时
比较的仍然是地址

List集合

List集合(接口):有序,可重复集合

        List list=new ArrayList();//向上造型
        
        System.out.println(list.size()); 集合当前的元素个数
        
        list.add(12); 集合添加元素
        list.add("abc");
        list.add("abc");
        
        System.out.println(list.size());
        
        System.out.println(list.get(0)); 提供下标获取元素
        System.out.println(list.get(1));
        System.out.println(list.get(2));
        
        删除集合中的与参数对象相同的元素
        如果参数是整数值时,删除对应下标的元素
        list.remove(0);
        list.remove("abc");
集合的遍历
        List list=new ArrayList();
        list.add("hello");
        list.add("tom");
        list.add("jack");
通过for循环遍历集合
        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }
for each 遍历集合
        
         * 冒号左边 声明一个对象表示集合中元素(数据类型对应)
         * 冒号右边 表示需要遍历的集合对象
         * 操作obj 就是操作实际元素 
        
for(Object obj:list){
    System.out.println(obj);    
}
* 通过迭代器(Iterator接口)遍历集合 
         * 
         * hasNext():判断游标的右边是否存在下一个元素
         * next():获取游标右边的元素,并且将游标向下移动
         * 
         * 使用迭代器遍历集合的过程中,如果需要删除元素
         * 只能使用迭代器提供的删除方法

        通过集合的iterator() 获取迭代器

        Iterator it=list.iterator();
        System.out.println(it.hasNext());
        while(it.hasNext()){
            System.out.println(it.next());
        }

ArrayList 集合底层是由Object[]实现的, 查询元素的效率更高

泛型:保证集合中的数据是相同的对象

List<Double> list=new ArrayList<Double>();

List集合中的元素如果是自定义类型(例 :Person),无法使用Collections.sort() 对该集合中的元素进行排序,因为自定义类本身不存在大小规则。

解决方法: 自定义类实现Comparable<T> ,可以对该类添加比较大小的规则(该类的对象之间比较大小)

public class Person implements Comparable<Person>{

/重写该方法 ,根据类的属性自定义比较大小的规则
    @Override
    public int compareTo(Person o) {
        // TODO Auto-generated method stub
        return this.age-o.age;
    }
}

Java定义好的类,已经实现了Comparable<T>接口
从而确定了自身比较大小的规则,如果该规则不适用于
我们的程序当中,可以重新定义一个比较器Comparator接口

public class ComparImp implements Comparator<String>{

    @Override
    public int compare(String s1, String s2) {
        // TODO Auto-generated method stub
        return s1.length()-s2.length();
    }

}
public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<String> list=new ArrayList<String>();
        ComparImp c=new ComparImp(); 比较器对象
        
        list.add("哈哈");
        list.add("不国人民");
        list.add("天真和");
        
        Collections.sort(list,c); 重载方法
    
        for(String s:list){
            System.out.println(s);
        }
    }
Set集合

set集合(接口):不存在重复元素,元素存取的顺序不同

        Set<String> set=new HashSet<String>(); 定义方式
        set.add("abc"); 添加元素
        set.add("哈哈");
        set.add("hello");
        set.add("abcdef");
        set.add("中国");
        System.out.println(set.size()); 集合元素个数
        
        System.out.println(set.isEmpty()); 判断集合是否为空
        
        System.out.println(set.contains("中国人"));判断集合是否包含该元素
        
        set.clear();清空集合
        
        遍历集合
        Iterator<String> it=set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }

TreeSet集合:会将内部元素按照元素自身的大小规则,升序排序

Map:存储元素以键值对的形式进行存储(key-value) ,其中key不可以重复

Map<String,Integer> map=new HashMap<String,Integer>(); 定义方式
        
        map.put("数学", 90); 添加元素
        map.put("英语", 90);
        map.put(null,null); map可以使用null作为key
        
        System.out.println(map.get("英语")); 通过key获取value
        
        System.out.println(map.remove("数学")); 通过key删除元素 key-value同时删除
        
        System.out.println(map.size()); 元素个数
        
        System.out.println(map.get("数学")); 如果key不存在,返回结果是null 
        
        System.out.println(map.get(null));
        
        System.out.println(map.containsKey("英语")); 判断map中是否包含key
遍历Map的三种方式
Map<String,Integer> map=new HashMap<String,Integer>();
        
        map.put("数学", 90);
        map.put("英语", 93);
        map.put("Java",92);
keySet() - Set<T> 将Map中所有的key 获取出来放入Set集合中
        Set<String> keySet= map.keySet();

        通过遍历set集合获取集合中的每一个key
        for(String key:keySet){
            System.out.println(map.get(key));
        }
* map底层实际上维护了一个Entry实例
* Entry提供了两个不同的方法,分别获取key和value

        Set<Entry<String,Integer>> entrySet=map.entrySet();
          for(Entry<String,Integer> entry:entrySet){
            System.out.println(entry.getKey()+":"+entry.getValue());
          }
values() 将map中所有的值获取出来 放入Collection中

Collection<Integer>  values=map.values();
    for(Integer value:values){
      System.out.println(value);
    }
File 文件类
        File f1=new File("D:/a.txt"); 定义方式
        
        File f2=new File("D:/hello");
        
        System.out.println(f1.exists()); 判断文件对象是否存在
        
        System.out.println(f1.length()); 获取文件的字节大小
        
        System.out.println(f1.getName()); 获取文件名
        
        System.out.println(f2.exists());  
        
        System.out.println(f2.getName());
        
        System.out.println(f1.getPath());获取文件路径
        
        System.out.println(f2.getPath());
        
        File[] files=f2.listFiles(); 获取目录下的子选项(文件和目录)
        System.out.println(files.length);
        for(File f:files){
            System.out.println(f.getName());
        }
public static void main(String[] args) {
        // TODO Auto-generated method stub
        File f1=new File("D:/b.txt");
        
        try {
            boolean flag=f1.createNewFile();
            if(flag){
                System.out.println("文件创建成功");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
public static void main(String[] args) {
        // TODO Auto-generated method stub
        File f1=new File("D:/hello");
        if(f1.mkdir()){
            System.out.println("目录创建成功");
        }
        
    }

先创建目录 再创建文件

public static void main(String[] args) {
        // TODO Auto-generated method stub
        //D:/hello/hello.txt
        File f1=new File("D:/hello");
        File f2=new File("D:/hello/hello.txt");
        if(f1.mkdir()){
            try {
                f2.createNewFile( );
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
}
public static void main(String[] args) {
        // TODO Auto-generated method stub
        File f1=new File("D:/n");
        
        //如果目录中存在子选项的话,无法直接删除该目录
        boolean flag=f1.delete();//删除文件和目录
        if(flag){
            System.out.println("目录删除成功");
        }else{
            System.out.println("目录删除失败");
        }
}

递归方法解决问题

public static void main(String[] args) {
        // TODO Auto-generated method stub
      将hello目录中的所有子文件以及子目录的文件名打印出来
    
         * listFiles(),isDirectory()
         * 
         * 首先获取一级目录下的所有子项
         * 遍历所有子项,如果是目录的话 继续遍历该子目录下的所有子项
         * 重复以上操作,直到没有目录为止
        
        File f=new File("D:/hello");
        getFile(f);
    }
    
    public static void getFile(File file){
        
            File[] files=file.listFiles();
            
            for(File f:files){
                if(f.isDirectory()){
                    System.out.println("目录:"+f.getName());
                    getFile(f);
                }else{
                    System.out.println("文件:"+f.getName());
                }
            }
            
    }

字节输入流

public static void main(String[] args) {
        // TODO Auto-generated method stub
        输入流 :将数据从外部(本地磁盘,网络)读取到程序中的流
        FileInputStream 属于字节流  
        FileInputStream(File f) ,FileInputStream(String url)

        File f=new File("D:/hello.txt");
        try {
            FileInputStream fis=new FileInputStream(f);
            
            byte [] buff=new byte[10];
            
            int len; 表每次读取文件信息的位置
            
            StringBuffer s=new StringBuffer();
            
            while((len=fis.read(buff))!=-1){
                
                new String(buff,0,len) 将字节数组中的内容转换字符串
                s.append(new String(buff,0,len));
            }
            
            System.out.println(s);
            
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

字节输出流

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        字节输出流
        File f=new File("D:/a.txt");
        构造器中加入参数 true 表示以追加的形式写入文件内容
        如果构造器中的文件路径不存在,则会将文件创建出来

        FileOutputStream fos=new FileOutputStream("D:/b.txt",true);
        
        String message="abc";
        
        byte[] buff=message.getBytes();
        
        fos.write(buff); 写出方法
        
        fos.close();
        System.out.println("文件写出完毕");
}

文件的复制

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        FileInputStream fis=new FileInputStream("D:/内存图.png");
        
        FileOutputStream fos=new FileOutputStream("D:/内存图1.png",true);
        
        byte[] buff=new byte[4];
        
        int len;
        
        while((len=fis.read(buff))!=-1){
            fos.write(buff, 0, len);
        }
        
        fis.close();
        fos.close();
        
        System.out.println("文件复制完毕...");
    }

字符流

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        InputStreamReader(FileInputStream fis)
        对于纯文本文件 字符流的读写效率更高,但是字符流只能读写纯文本文件
        long time1=System.currentTimeMillis();当前时间到1970-1-1所经历的毫秒值

        FileInputStream fis=new FileInputStream("D:/a.txt");
        InputStreamReader isr=new InputStreamReader(fis);字符输入流
        
        char[] cuff=new char[5];
        
        int len;
        StringBuffer s=new StringBuffer();
        while((len=isr.read(cuff))!=-1){
            s.append(new String(cuff,0,len));
        }
        
        isr.close();
        long time2=System.currentTimeMillis();
        
        System.out.println(time2-time1);
        
    }

字符串输入流的内容 维护了一个字符缓冲区每一次写出的数据并不能直接写入到文件中而是存放在缓冲区中,只有关闭流时,会将缓冲区中的数据 全部写出

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        FileOutputStream fos=new FileOutputStream("D:/b.txt",true);
        OutputStreamWriter osw=new OutputStreamWriter(fos);
        String message="大集合";
        osw.write(message);
        osw.flush();  该方法会将缓冲区的内容一次性写出
        osw.close();
        System.out.println("写出完毕...");
    }

高级流 ,处理流

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        BufferedInputStream 高级流(处理流) 输入流

        FileInputStream fis=new FileInputStream("D:/b.txt");
        BufferedInputStream bis=new BufferedInputStream(fis);
        
        byte[] buff=new byte[4];
        
        int len;
        
        StringBuffer s=new StringBuffer();
        
        while((len=bis.read(buff))!=-1){
            s.append(new String(buff,0,len));
        }
        
        System.out.println(s);
    }
public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        FileOutputStream fos=new FileOutputStream("D:/c.txt");
        BufferedOutputStream bos=new BufferedOutputStream(fos);
        String message="大家好...";
        byte[] buff=message.getBytes();
        bos.write(buff);
        bos.close();  方法的内部,调用了flush()
    }

实现多线程的方式

线程的方法

Thread.currentThread() 返回当前正在执行线程对象

getName() 线程名
da.setName("线程da"); 设置线程名.

setPriority(Thread.MAX_PRIORITY);//设置线程优先级方法

start(); 启动线程,启动线程之后会自动调用线程对应的run方法

Thread.sleep(100); 当前线程会睡眠100毫秒之后 ,再继续执行

join() ,在线程A中 调用线程B的join(),则线程A 会等待线程B执行结束

线程的生命周期

线程的生命周期.png

线程安全问题

多个线程对象访问同一个资源,导致数据错乱

public class ThreadDemo implements Runnable{
    /*
     * 多线程存在线程安全问题
     * 多个线程对象访问同一个资源,导致数据错乱
     */
    static int n=100; //表示100张车票
    
    @Override
    public void run() {
        while(n>0){
            
            shellNum();
        }
    }
    /*
     * synchronized 同步关键字 ,同步方法
     * 只有当前进入方法的线程执行完毕后,其他
     * 线程才可以进入方法
     */
    public synchronized void shellNum(){
        if(n>0){
            System.out.println(Thread.currentThread()
                    .getName()+" 卖出了第"+n+"张票");
            n--;
        }
    }

}
网络编程

网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输。

为了能够方便的识别网络上的每个设备,网络中的每个设备都会有一个唯一的数字标识,这个就是IP地址。在计算机网络中,现在命名IP地址的规定是IPv4协议,该协议规定每个IP地址由4个0-255之间的数字组成,例如10.0.120.34。每个接入网络的计算机都拥有唯一的IP地址,这个IP地址可能是固定的,例如网络上各种各样的服务器,也可以是动态的,例如使用ADSL拨号上网的宽带用户,无论以何种方式获得或是否是固定的,每个计算机在联网以后都拥有一个唯一的合法IP地址,就像每个手机号码一样

IP地址解决了在网络中找到一个计算机的问题,但是为了让一个计算机可以同时运行多个网络程序,就引入了另外一个概念——端口(port)。

在同一个计算机中每个程序对应唯一的端口,这样一个计算机上就可以通过端口区分发送给每个端口的数据了,换句话说,也就是一个计算机上可以并发运行多个网络程序,而不会在互相之间产生干扰。

在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的程序被称作服务器端(Server)程序,简称服务器。一旦通讯建立,则客户端和服务器端完全一样,没有本质的区别。

例如QQ程序,每个QQ用户安装的都是QQ客户端程序,而QQ服务器端程序则运行在腾讯公司的机房中,为大量的QQ用户提供服务。这种网络编程的结构被称作客户端/服务器结构,也叫做Client/Server结构,简称C/S结构。

网络通信方式

客户端

public static void main(String[] args) throws UnknownHostException, IOException {
        // TODO Auto-generated method stub
        int port=8088;//表示服务端的端口号
        String ip="localhost";//表示本机IP
        String message="服务端 hello";//项服务器发送的消息
        //创建客户端
        Socket socket=new Socket(ip,port);
        System.out.println("客户端已启动...");
        //获取网络输出流 向服务端发送消息
        OutputStream os=socket.getOutputStream();
        OutputStreamWriter osw=new OutputStreamWriter(os);
        osw.write(message);
        osw.flush();
        //关闭socket
        socket.close();
    }

服务端

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //创建服务端 设置端口号
        ServerSocket ss =new ServerSocket(8088);
        System.out.println("服务端已启动...");
        //accept(); 是一个阻塞方法 ,该方法在监听是否
        //有客户端连接到该服务端,没有客户端连接,该方法会一直阻塞
        //该方法可以获取socket对象 用于获取客户端的内容
        Socket socket=ss.accept();
        System.out.println("客户端已连接...");
        //获取网络输入流 读取客户端信息
        InputStream is=socket.getInputStream();
        InputStreamReader isr=new InputStreamReader(is);
        char[] chff=new char[20];
        int len;
        String message="";
        while((len=isr.read(chff))!=-1){
            message=new String(chff,0,len);
        }
        System.out.println("客户端:"+message);
        //关闭socket
        socket.close();
    }

持续交互

public static void main(String[] args) throws UnknownHostException, IOException {
        // TODO Auto-generated method stub
        Scanner scan=new Scanner(System.in);
        int port =8088;
        String ip="localhost";
        
        System.out.println("客户端已连接...");
        while(true){
            Socket socket=new Socket(ip,port);
            System.out.println("请发送消息:");
            String message=scan.next();//客户端发送给服务端
            OutputStream os=socket.getOutputStream();
            OutputStreamWriter osw =new OutputStreamWriter(os);
            osw.write(message);
            osw.flush();
            socket.shutdownOutput();//本次输出流结束
            if("exit".equals(message)){
                socket.close();
                break;
            }
            
            //接收服务端响应的信息
            InputStream is=socket.getInputStream();
            InputStreamReader isr=new InputStreamReader(is);
            char[] chff=new char[20];
            int len;
            String mes="";
            while((len=isr.read(chff))!=-1){
                mes=mes+new String(chff,0,len);
            }
            System.out.println("服务端回复:"+mes);
        }
        
    }
public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        Scanner scan=new Scanner(System.in);
        //创建服务端 设置端口
        ServerSocket ss=new ServerSocket(8088);
        System.out.println("服务端已启动...");
        while(true){
            //socket可以获取网络输入流  - 得到客户端的消息
            Socket socket=ss.accept();
            InputStream is=socket.getInputStream();
            InputStreamReader isr=new InputStreamReader(is);
            char[] chff=new char[20];
            int len;
            String message="";
            while((len=isr.read(chff))!=-1){
                message=message+new String(chff,0,len);
            }
            if("exit".equals(message)){
                socket.close();
                break;
            }
            System.out.println("客户端:"+message);
            
            //对客户端做出响应
            OutputStream os=socket.getOutputStream();
            OutputStreamWriter osw=new OutputStreamWriter(os);
            System.out.println("回复客户端:");
            String mse=scan.next();//回复给客户端的内容
            osw.write(mse);
            osw.flush();
            socket.shutdownOutput();
        }
        
        
    }

一个服务端对应多个客户端

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        Scanner scan=new Scanner(System.in);
        //创建服务端 设置端口
        ServerSocket ss=new ServerSocket(8088);
        System.out.println("服务端已启动...");
        while(true){
            //socket可以获取网络输入流  - 得到客户端的消息
            Socket socket=ss.accept();
            ServerThread st=new ServerThread(socket);
            Thread t=new Thread(st);
            t.start();
        }
    }

public class ServerThread implements Runnable{

    private Socket socket;
    
    public ServerThread(Socket socket) {
        
        this.socket = socket;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        start();
    }
    
    public void start(){
        Scanner scan=new Scanner(System.in);
        InputStream is;
        try {
            is = socket.getInputStream();
            InputStreamReader isr=new InputStreamReader(is);
            char[] chff=new char[20];
            int len;
            String message="";
            while((len=isr.read(chff))!=-1){
                message=message+new String(chff,0,len);
            }
            if("exit".equals(message)){
                socket.close();
                return;
            }
            //getInetAddress() 获取客户端IP
            System.out.println("客户端"+socket.getInetAddress()+":"+message);
            
            //对客户端做出响应
            OutputStream os=socket.getOutputStream();
            OutputStreamWriter osw=new OutputStreamWriter(os);
            System.out.println("回复客户端:");
            String mse=scan.next();//回复给客户端的内容
            osw.write(mse);
            osw.flush();
            socket.shutdownOutput();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

public class ClientA {

    public static void main(String[] args) throws UnknownHostException, IOException {
        // TODO Auto-generated method stub
        Scanner scan=new Scanner(System.in);
        int port =8088;
        String ip="localhost";
        
        System.out.println("客户端A已连接...");
        while(true){
            Socket socket=new Socket(ip,port);
            System.out.println("请发送消息:");
            String message=scan.next();//客户端发送给服务端
            OutputStream os=socket.getOutputStream();
            OutputStreamWriter osw =new OutputStreamWriter(os);
            osw.write(message);
            osw.flush();
            socket.shutdownOutput();//本次输出流结束
            if("exit".equals(message)){
                socket.close();
                break;
            }
            
            //接收服务端响应的信息
            InputStream is=socket.getInputStream();
            InputStreamReader isr=new InputStreamReader(is);
            char[] chff=new char[20];
            int len;
            String mes="";
            while((len=isr.read(chff))!=-1){
                mes=mes+new String(chff,0,len);
            }
            System.out.println("服务端回复:"+mes);
        }
    }

}
public class ClientB {

    public static void main(String[] args) throws UnknownHostException, IOException {
        // TODO Auto-generated method stub
        Scanner scan=new Scanner(System.in);
        int port =8088;
        String ip="localhost";
        
        System.out.println("客户端B已连接...");
        while(true){
            Socket socket=new Socket(ip,port);
            System.out.println("请发送消息:");
            String message=scan.next();//客户端发送给服务端
            OutputStream os=socket.getOutputStream();
            OutputStreamWriter osw =new OutputStreamWriter(os);
            osw.write(message);
            osw.flush();
            socket.shutdownOutput();//本次输出流结束
            if("exit".equals(message)){
                socket.close();
                break;
            }
            
            //接收服务端响应的信息
            InputStream is=socket.getInputStream();
            InputStreamReader isr=new InputStreamReader(is);
            char[] chff=new char[20];
            int len;
            String mes="";
            while((len=isr.read(chff))!=-1){
                mes=mes+new String(chff,0,len);
            }
            System.out.println("服务端回复:"+mes);
        }
    }

}

内部类

无论外部类是否继承其他类,不会影响内部类的继承关系
从而解决了Java中单一继承的缺点

public class Outer1{
    private String name="Outer1";
    private int out1=10;
    static int out=11;
    public void say(){
        System.out.println("Outer");
        调用内部的属性和方法 需要创建内部类对象
        Inner inner=new Inner();
        inner.getInner();//调用的内部类方法
    }
    内部类 无法声明static属性/方法
    可以声明 static final修饰的属性
    可以访问外部类的属性和方法(包含 private ,static)
    class Inner extends{内部类
        private int i=5;
        static final int inn1=6;
        String inName="inner";
        
        public  void getInner(){
            System.out.println("inner");
            System.out.println(name);
            System.out.println(out);
        }
    }
}
public class Test1 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        外部类名.内部类名 内部类对象 = 外部类对象.new 内部类构造器;
        Outer1 out1=new Outer1();
        Outer1.Inner inner=out1.new Inner();
        
        System.out.println();
    }

}

上一篇下一篇

猜你喜欢

热点阅读