java基础总结

java难点

针对个人不足的地方进行强化。

  • java诞生于1995年,正式发布第一个版本,开始叫C++--
  • 2006年java进军大数据:Hadoop

1.dos命令

//无包
javac hello.java  //编译为class文件
java  hello		//运行class文件
//有包
有包的情况在编译后运行时要把包加上,注意编译的路径, -d .代表在当前目录创建目录,包名就是文件夹,要和创建的目录对应起来
javac -d . Hello.java  //从当前位置开始创建目录进行编译
java com.xiaoxiao.test.Hello  //运行class文件
    

//使用javadoc生成api文档
javadoc -encoding UTF-8 -charset utf-8 Hello.java
//也可在IDE中直接生成

2.java代码块

  • java程序的启动并运行的过程

    image-20220708085210560

    • 非静态属性:创建对象后,系统会自动给对象中的非静态属性做初始化赋默认值,也正是因为这个 原因,非静态属性只有在创建对象后,使用对象才能访问。
    • 静态属性:类加载到内存中(方法区)的时候,系统就会给类中的静态属性做初始化赋默认值,所以,即使还没有创建对象,只要这个类加载到了内存,就可以直接使用类名来访问静态属性,因为这个时候静态属性已经完成了初始化赋默认值的操作。
  • 静态代码块:在类中定义,使用static关键字声明,在类被加载时就运行了,而且只会运行一次,优先于各种代码块和函数;如果一个类中有多个静态代码块,会依次执行。如一些项目的配置文件的加载,常常放在static代码块中。

  • 构造代码块(无static修饰的):创建对象时调用,每创建一次会调用一次,优先于构造函数。可用于创建对象的次数统计等等。

  • 执行顺序:静态代码块-->构造代码块(new的时候)-->构造方法

    image-20220622140249500

    //static关键字实例
    public class StaticDemo {
        public static void main(String[] args) {
            Student.Address address=new Student.Address("成都","10086");
            Student student=new Student("韩信","男",address);
            student.printInfo();
        }
    
    
    }
    class Student{
        public static class Address{
            private String city;
            private String zipCode;//邮编
    
            public Address(String city, String zipCode) {
                this.city = city;
                this.zipCode = zipCode;
            }
    
            @Override
            public String toString() {
                return "Address{" +
                        "city='" + city + '\'' +
                        ", zipCode='" + zipCode + '\'' +
                        '}';
            }
        }
        private String name;
        private String gender;
        private Address address;
    
        public Student(String name, String gender, Address address) {
            this.name = name;
            this.gender = gender;
            this.address = address;
        }
        void printInfo(){
            System.out.println("name="+this.name);
            System.out.println("gender="+this.gender);
            System.out.println(this.address);
        }
    }
    /*输出:
    main方法执行
    静态代码块
    构造代码块
    无参构造器代码块
    方法代码块
    *****************************
    构造代码块
    有参构造器代码块
    方法代码块*/
    
    //通过反编译,可以看出,程序的class文件中,构造方法中前面加入了构造代码块的内容
        public CodeDemo(int a) {
            System.out.println("构造代码块");
            this.a = a;
            System.out.println("有参构造器代码块");
        }
    
        public CodeDemo() {
            System.out.println("构造代码块");
            System.out.println("无参构造器代码块");
        }
    
    

3.java内部类

  • 内部类的分类:内部类不能访问外部类方法中的局部变量,除非变量是final的 (一般发生在方法中定义的内部类)

    • 静态内部类:有static关键字修饰的内部类

      /**
       * 静态内部类->静态内部类是不依附于外部类对象的(不需要创建外部类对象就可以实例化),轻量级,加载外部类时,静态内部类就会被加载,只需要加载一次,用的较多
       * 核心:学习静态内部类需要联想静态变量来理解
       * 1.定义位置
       *  在类中,方法体和代码块之外,并且必须使用static来修饰
       * 2.定义语法
       *  [修饰符] class 外部类{
       *      [修饰符] static class 静态内部类
       *  }
       * 3.注意事项
       *  a)在静态内部类中,不但可以定义成员变量、成员方法、构造方法和构造代码块,还能定义静态变量、静态方法和静态代码块,与平常类相同
       *  b)静态内部类中,只能操作外部类的静态变量和静态方法,静态不能访问非静态
       *  c)使用静态内部类时,无需创建外部类对象,直接通过外部类类名就可以操作静态内部类的静态变量和静态方法
       *      调用静态变量:外部类.静态内部类.静态变量
       *      调用静态方法:外部类.静态内部类.静态方法(实参列表)
       * 4.静态内部类的创建方式
       *  a)在外部类里面创建:
       *      语法:静态内部类 对象=new 静态内部类(实参)
       *  b)在外部类外面创建:
       *      语法:外部类.静态内部类 对象=new 外部类.静态内部类(实参)
       */
      public class InnerClassDemo {
          public static void main(String[] args) {
              OuterClass outerClass = new OuterClass();
              outerClass.create1();
              System.out.println("*****************************");
              OuterClass.create2();
              System.out.println("*****************************");
              OuterClass.InnerClass innerClass = new OuterClass.InnerClass(10);
              innerClass.eat();
              System.out.println("*****************************");
              System.out.println(OuterClass.InnerClass.num2);
              OuterClass.InnerClass.study();
          }
      }
      //外部类
      class OuterClass{
          static int age=50;
          public void OuterEat(){
              System.out.println("outereat ...");
          }
          static public void OuterStudy(){
              System.out.println("outerstudy ...");
          }
          public void create1(){
              InnerClass innerClass = new InnerClass(10);//创建对象时,默认会初使化静态内部类中的代码块和静态代码块,静态代码块只执行一次
              System.out.println(innerClass.num1);
              innerClass.eat();
          }
          public static void create2(){
              InnerClass innerClass = new InnerClass(10);
              System.out.println(innerClass.num1);
              innerClass.eat();
          }
          //静态内部类
          public static class InnerClass{
              {
                  System.out.println("代码块");
                  System.out.println(age);//代码块优于构造方法执行
                  OuterStudy();
              }
              static {
                  System.out.println("静态代码块");
              }
              int num1=15;
              static int num2;
              public InnerClass(int num1) {
                  this.num1 = num1;
                  System.out.println("构造方法");
              }
              public void eat(){
                  System.out.println("eat ...");
              }
              public static void study(){
                  System.out.println("study ...");
              }
          }
      }
      
    • 非静态内部类:

      • 无static关键字修饰的内部类,需要依赖于外部类的对象,非静态内部类的使用就是将内部类当作一个成员变量或成员方法。
      //非静态内部类实例
      public class NonStaticInnerClassDemo {
          public static void main(String[] args) {
              OuterClassTest outerClass = new OuterClassTest();
              outerClass.disPlay();
              System.out.println("*****************************");
              OuterClassTest.InnerClass innerClass = outerClass.new InnerClass();//需要依赖于外部类对象进行创建
              innerClass.disPlay();
          }
      }
      class OuterClassTest{
          String name;
          public void disPlay(){
              System.out.println("非静态外部类");
              System.out.println(name);
          }
          class InnerClass{
              String name;
              public InnerClass() {
                  this.name="韩信";
              }
              public void disPlay(){
                  System.out.println("非静态内部类");
                  System.out.println(name);
              }
          }
      }
      

      image-20220621174528680

      • 非静态内部类也可以定义在方法中。
      //非静态内部类实例
      public class NonStaticInnerClassDemo02 {
          public static void main(String[] args) {
              new OuterClassTest2().disPlay();
          }
      }
      
      class OuterClassTest2 {
          String name;
          public void disPlay() {
              //不能用public修饰
              class InnerClass2 {
                  public void print(){
                      System.out.println("innerClass ....");
                  }
              }
              new InnerClass2().print();
          }
      }
      
      
    • 匿名内部类

      • 传统的接口的实现:
      public class NonNamedInnerClassDemo {
          public static void main(String[] args) {
              MyInterface myImplenment = new MyImplenment();
              myImplenment.test();
          }
      }
      //接口
      public interface MyInterface {
          void test();
          void eat();
      }
      //实现类
      public class MyImplenment implements MyInterface{
          @Override
          public void test() {
              System.out.println("test1");
          }
          @Override
          public void eat() {
              System.out.println("eat1");
          }
      }
      
      • 使用匿名内部类:
      //匿名内部类
      public class NonNamedInnerClassDemo {
          public static void main(String[] args) {
              MyInterface myImplenment = new MyInterface() {
                  @Override
                  public void test() {
                      System.out.println("test2");
                  }
      
                  @Override
                  public void eat() {
                      System.out.println("eat2");
                  }
              };
              myImplenment.test();
              myImplenment.eat();
          }
      
      }
      
      • 使用普通内部类:
      public class NonNamedInnerClassDemo {
          public static void main(String[] args) {
      
              MyImplent myImplent = new NonNamedInnerClassDemo().new MyImplent();
              myImplent.eat();
              myImplent.test();
          }
          class MyImplent implements MyInterface{
      
              @Override
              public void test() {
                  System.out.println("test3");
              }
      
              @Override
              public void eat() {
                  System.out.println("eat3");
              }
          }
      }
      
      • 使用静态内部类:
      public class NonNamedInnerClassDemo {
          public static void main(String[] args) {
              MyImplent myImplent = new MyImplent();
              myImplent.eat();
              myImplent.test();
          }
         static class MyImplent implements MyInterface{
      
              @Override
              public void test() {
                  System.out.println("test4");
              }
      
              @Override
              public void eat() {
                  System.out.println("eat4");
              }
          }
      }
      
  • 为什么要使用内部类

    • 如果一个类仅仅对另一个类有用时,从逻辑上讲,应该把它们放在一起,因此把它们放在一起是很合乎逻辑的,把它们嵌套起来,可以使程序包更加简化
    • 面向对象的准则就是封装和信息隐藏,使用嵌套类可以实现对外界的信息隐藏
    • 代码的可读性和可维护性增强

4.java关键字

image-20220621094829691

  • assert:assert常用在程序调试中,这个关键字可以判断布尔值的结果是否和预期的一样,如果一样就正常执行,否则会抛出AssertionError。语法有两种,一般很少使用,默认是关闭断言的,需要vm中加参数-ea开启

    • assert <boolean表达式>

      如果<boolean表达式>为true,则程序继续执行。

      如果为false,则程序抛出AssertionError,并终止执行。

    • assert <boolean表达式> : <错误信息表达式>

      如果<boolean表达式>为true,则程序继续执行。

      如果为false,则程序抛出java.lang.AssertionError,并输入<错误信息表达式>。

    //assert :断言 与if语句相仿
    //assert <boolean表达式>
    //如果<boolean表达式>为true,则程序继续执行。
    //如果为false,则程序抛出AssertionError,并终止执行。
    //
    //assert <boolean表达式> : <错误信息表达式>
    //如果<boolean表达式>为true,则程序继续执行。
    //如果为false,则程序抛出java.lang.AssertionError,并输入<错误信息表达式>。
    public class AssertDemo {
        public static void main(String[] args) {
            int a=8;
            int b=9;
            assert a>b:"这里有错误";
        }
    }
    

    image-20220621100656907

  • final:最终的

    final修饰类:该类不可继承,如String类就是final修饰,不能被继承

    final修饰方法:该方法不能被子类覆盖(但它不能修饰构造函数)

    final修饰字段属性:常量,属性值第一次初始化后不能被修改,必须赋初值

    final修饰参数:方法中不允许对参数值进行修改,基本数据类型和引用类型不一样,引用类型可以进行属性的设置

    使用final可以提高程序执行的效率,将一个方法设成final后编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。

    public class Demo {
        public static void main(String[] args) {
            final int c=99;
            System.out.println(c);
        }
    
    }
    class User{
      int ID;
      String name;
    }
    final class Person1 {
        public void Test1(final int num){
            //num=99;不能修改由final修饰的参数值
        }
        public void Test2(final User user) {
            // user=new User();引用类型同样不可重新赋值
        }
        public void Test3(final User user) {
            //属性是可以赋值的
           user.ID=11;
           user.name="han";
        }
            
    }
    //class Student extends Person{},不能继承被final修饰的类
    class Person2{
        public final void Test(){
            System.out.println("Person2");
        }
    }
    class Student2 extends Person2{
        ///public void Test(){},不能重写由final修饰的方法
    }
    
  • static:静态的

    静态属性:属于类,程序编译时加载到内存中。

    静态方法:可通过类名直接调用,类加载时已经初始化,属于类,静态方法只能访问静态属性和静态方法,成员方法可以访问成员属性和成员方法,静态成员在类加载时就创建了,是对象公共的。

    image-20220622135039534

    public class Test{
        static String name1;
         String name2;
         String name3;
         static void Method1(){
             name1="static-han";
             System.out.println(name1);
             //name2="";报错
        }
        void Method2(){
             name1="non-static-han";
            System.out.println(name1);
            name2="bang";
            System.out.println(name2);
            name3="sheng";
            System.out.println(name3);
        }
        public static void main(String[] args) {
            Test test = new Test();
            test.Method2();
            Test.Method1();
        }
    }   
    

    静态代码块:修饰块,只运行一次,一般放需要加载的配置文件。

    静态嵌套类:不能修饰顶级类,可通过static声明一个嵌套类,此时静态嵌套类是顶级类的一个静态成员,只能访问所属类的静态成员,具体上面有介绍。

    静态导包:在导包时加上static,可以省略类名。

  • const、goto:Java中没有const,没有goto 这些关键字是其预留字而非已经有的关键字。意味着这些关键字不能现在被使用,可能在java的某个版本中被提上正位。

  • private、protected、public、默认的权限

    image-20220622142022289

  • native

    • native关键字用来标识jvm调用外部的c或c++动态库,代表本地方法
    • javah命令,生成对应的.h头文件,要先学习c或c++,不必深究
  • scrictfp

    • 关键字strictfp是strict float point的缩写,指的是精确浮点,它是用来确保浮点数运算的准确性。
    • JVM在执行浮点数运算时,如果没有指定strictfp关键字,此时计算结果可能会不精确,而且计算结果在不同平台或厂商的虚拟机上会有不同的结果,导致意想不到的错误。
    • 而一旦使用了strictfp来声明一个类、接口或者方法,那么在所声明的范围内,Java编译器以及运行环境会完全依照IEEE二进制浮点数算术标准来执行,在这个关键字声明的范围内所有浮点数的计算都是精确的。
    • 需要注意的是,当一个类被strictfp修饰时,所有方法都会自动被strictfp修饰。
    • 因此,strictfp可以保证浮点数运算的精确性,而且在不同的硬件平台会有一致的运行结果。
    /**
     * strictfp:strict float point精确浮点数,可以在不同的硬件平台保证浮点数的精确运算
     * 当一个类被strictfp修饰时,所有方法都会自动被strictfp修饰。
     */
    public  class Test02 {
        public static void main(String[] args) {
            double a=0.03496421f;
            double b=0.12365;
            System.out.println(Add.addnums(a, b));
        }
    }
    strictfp class Add{
        public static double addnums(double num1,double num2){
            return num1+num2;
        }
    }
    
  • synchronized:

    • 线程同步:

      synchronized(Object) {
        //业务代码
      }
      
  • throw、throws

    image-20220623170351628

  • transient

    • 在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。
  • volatile:易挥发的,使用volatile可以保证线程之间的可见性及禁止指令重排序,不保证原子性,是轻量级的synchronized,可以在一定条件下保证线程安全

    image-20220623174708700

    • 可见性:在一个地方进行写操作,在另一个地方是否能立即读取到修改后的值

      • 如下列的单线程程序可见性是很明显的。
      public class Demo01 {
          public static void main(String[] args) {
              boolean a=true;
              a=false;
              System.out.println(a);//这里可以立即读取到a的值,可见性很明显
          }
      }
      
      • 对于多线程
      public class Demo01 {
          static volatile boolean a = true;//加入volatile可以保证可见性
          public static void main(String[] args) throws InterruptedException {
                  //开启一个新线程
                  new Thread(() -> {
                      while (a) {
                          //如果不加volatile,则a对新创建的这个线程是不可见的,会导致死循环,此时a读取的是cpu的缓存,而不是主存
                      }
                  }).start();
                  System.out.println(Thread.currentThread().getName());
                  Thread.sleep(1000);//主线程阻塞1秒
                  a = false;
                  System.out.println(a);
          }
      }
      

5.switch

  • JDK7开始支持字符串
  • case有穿透现象(不写break)

6.命令行传参

  • 可以通过java命令加参数给main方法传递参数

7.排序算法

  • 链接
    • 冒泡排序:元素两两比较交换位置,大的元素后移,每一轮比上一轮少一次
    • 选择排序:从索引0处开始,依次和后面的元素比较,小的元素前移,每一轮比上一轮少一次
    • 直接插入排序:从索引1开始,每个数和前一个数进行比较,小的往前,大的不变
    • 希尔排序:是直接插入排序的优化,通过设置步长,对相同步长间隔的元素进行比较,不断缩减步长,最终使步长为1,通常设置步长为克努特(Kunth)间隔数列:h=3h+1--->1、4、13、40、121、364...
    • 快速排序:在待排序的数列中,我们首先要找一个数字作为基准数。一般选择第 1 个数字作为基准数(其实选择第几个并没有关系)。接下来我们需要把这个待排序的数列中小于基准数的元素移动到待排序的数列的左边,把大于基准数的元素移动到待排序的数列的右边。这时,左右两个分区的元素就相对有序了;接着把两个分区的元素分别按照上面两种方法继续对每个分区找出基准数,然后移动,直到各个分区只有一个数时为止。
    • 归并排序:“分而治之”,先将数列分成长度为1的子数列,排序后,两两归并,归并后的子数列继续两两归并
    • 基数排序:通过分配再收集的方式进行数据排序,先将数据按个位从前往后、从上往下的方式排列后取出(可以看成10个桶),再按10位重复上面的方法,百位、千位...
    • 堆排序:将数组按完全二叉树的结构排列,从最后一个非叶子节点开始转,转成大顶堆,将根节点的元素和最后一个元素进行交换,重新转成大顶堆,如此往复
      • 将待排序的数列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。
      • 将其与末尾元素进行交换,此时末尾就是最大值
      • 然后剩余n-1个元素重新构造成一人上大顶堆,这样就会得到n个元素的次大值
      • 反复执行,最终可以排序为有序序列

8.单例模式

  • 构造器私有

  • 饿汉式:如果单例中成员多,会浪费空间

    package DanLi;
    //饿汉式单例:先创建实例
    public class Hungry {
        //单例:构造器私有,只允许在内部创建实例
        private Hungry(){
        }
        //考虑到反射的存在,需要加上final
        public final static Hungry HUNGRY=new Hungry();
        public static Hungry getHungry(){
            return HUNGRY;
        }
    }
    
  • 懒汉式:使用volatile双重检查机制来控制线程的安全

  • 使用静态内部类的方式

  • 使用枚举

9.多态

  • 父类的引用指向子类Person person=new Son();,调用方法会执行子类的方法
  • instanceof:对象 instanceof 类:如果对象是类的或其子类的实现,则返回true

10.异常

image-20220624225420215

11.Stringbuilder

  • string是不可变的
  • StringBuffer:线程安全的,StringBuffer的底层是一个char类型的数组,如果没有明确设定,则系统会自动创建一个长度为16的char类型数组,在使用数组的时候,如果长度不够了,则会通过拷贝对数组进行扩容
  • StringBilder:线程不安全,但是效率高,适用于单线程
public class Demo02 {
    public static void main(String[] args) {
        String str1="a"+1+2;
        String str2='a'+1+2+"";
        String str3=1+2+"a";
        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);
    }
}
//输出:
a12
100
3a    

12.集合框架

image-20220624230439724

13.输入输出流

image-20220708100706090

image-20220708105628502

  • 字节流:InputStream、outputStream
    • 节点流:有实际传输数据的读写功能,常用共有6种,FileInputStream、FileOutputStream、ByteArrayInputStream、ByteArrayOutputStream、FileReader、FileWriter
      • FileInputStream、FileOutputStream,读取二进制文件用此种方式,因为二进制文件没有编码方式的概念,如图片
  • 字符流:Reder、Writer
    • 节点流:有实际传输数据的读写功能
      • FileReader、FileWriter,读取有编码方式文件用此种方式,如txt文件,是转换流的子类
  • 处理流:
    • filter过滤流,在节点流的基础之上增强功能
      • buffer缓冲区:中间加一个缓冲,让读取写入更加高效
        • bufferedInputStream
        • bufferedOutputStream
        • bufferedReader
        • bufferedWriter
      • Object对象流:也是一种过滤流的一种,要基于节点流进行操作,序列化类必须要实现Serializable接口,使用transient(瞬间的)修饰属性,则这个属性不能序列化
        • ObjectOutputStream
        • ObjectInputStream
    • 转换流:将字节流转换成字符流
      • inputstreamReader
      • outputstreamWriter

14.多线程

  • 静态代理模式:new Thread(Runnable runnable).start();

  • lambda表达式,适用于函数式接口,new Thread(()->{xxxx}).start()

  • 线程状态

    • 新建状态
    • 就绪
    • 运行
    • 阻塞
    • 死亡
  • 线程同步

    • 多个对象操作同一个资源,并发

    • 队列+锁

    • Synchronized

      • 同步方法
      • 同步块
      • 第一个线程进来拿到锁,后面就要排队了,直到这个人释放锁,后面拿到锁才能进去
      • 死锁:两个人都抱着对方的锁
        • 死锁形成的条件,破坏其中一个就能解决
          • 互斥:一个资源每次只能被一个线程使用。
          • 请求与保持:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
          • 不剥夺条件:线程已获得的资源,在未使用完之前,不能强行剥夺。
          • 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
      public class DeadLockDemo {
      
          public static void main(String[] args) {
              // 线程a
              Thread td1 = new Thread(new Runnable() {
                  public void run() {
                      DeadLockDemo.method1();
                  }
              });
              // 线程b
              Thread td2 = new Thread(new Runnable() {
                  public void run() {
                      DeadLockDemo.method2();
                  }
              });
      
              td1.start();
              td2.start();
          }
      
          public static void method1() {
              synchronized (String.class) {
                  try {
                      Thread.sleep(2000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  System.out.println("线程a尝试获取integer.class");
                  synchronized (Integer.class) {
      
                  }
      
              }
          }
      
          public static void method2() {
              synchronized (Integer.class) {
                  try {
                      Thread.sleep(2000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  System.out.println("线程b尝试获取String.class");
                  synchronized (String.class) {
      
                  }
      
              }
          }
      
      }
      
    • Lock锁(优先级Lock>Synchronized同步块>Synchronized同步方法):Reentrantlock

      • 显式同步
        • lock
        • unlock
  • 线程通讯

    • 缓冲区:消息队列
    • 标识们:红绿灯
    • wait()
    • notifyAll()

15.网络编程

image-20220711095222003

16.GUI

image-20220711100310585

17.注解和反射

image-20220711100957800

posted @ 2022-07-11 10:19  是韩信啊  阅读(18)  评论(0编辑  收藏  举报