zoukankan      html  css  js  c++  java
  • java知识点总结ing

    一、面向对象基础

    0、类和对象

      对象:是具体的事物 xiaoming xiaohong 类:是对对象的抽象(抽象 抽出象的部分)Person
      先有具体的对象,然后抽象各个对象之间象的部分,归纳出类通过类再认识其他对象。
      【生活案例】 

        类是一个图纸   对象是根据该图纸制造多个实物

        类是一个模具    对象是使用模具制造的多个铸件(月饼模子 )

        类是上海大众汽车,对象就是大家购买的一辆辆具体上海大众汽车

        

    1、内存分析

      (1)程序执行过程  

          

                         

          

      (2)容易造成内存泄漏的操作

        

    2、构造器

     

    3、this

     4、static关键字

       static修饰的成员变量和方法,从属于类。               

      普通变量和方法,从属于对象

        ① 静态方法不能访问非静态成员【非静态成员必须有具体的类对象才可以访问】

        ② 非静态方法可以访问静态成员

    class TS2{
        public int i = 20;
        private static TS2 ts = new TS2();
        
        // 限制通过new生成类对象
        private TS2() {    
        }
        
        public static TS2 getTS2() {     //static是一定不能省略的,因为不能创建对象,只能由类来访问,所以得设置成静态方法
            return ts;
        }
    }
    public class TestStatic2 {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    //        TS2 ts = new TS2();          //error,因为构造方法是private类型的,不能直接通过new构造新对象
            
            TS2 ts0 = TS2.getTS2();
            TS2 ts1 = TS2.getTS2();
            ts0.i = 99;
            System.out.printf("%d
    ",ts1.i);    //99,证明 ts0和ts1是同一个对象
            if(ts0 == ts1) {
                System.out.println("ts0和ts1相等");    //ts0和ts1相等
            }else {
                System.out.println("ts0和ts1相等");
            }
            
        }
    
    }

    5、参数值传递

    6、package(同一个包里不能有同名的类)

           

           

           

           

    二、面向对象进阶

     0、继承使用要点

    (1)Java中只有单继承:Java中类没有多继承,接口有多继承。

    (2)如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object。

    (3)使用ctrl+T方便查看类的继承层次结构。

    (4)instanceof:是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true,否则返回false。

     1.1、方法重载 overload:

       指在一个类中,多个方法的方法名相同,但是参数列表不同。参数列表不同指的是参数个数、参数类型或者参数的顺序不同。                 

                   【选择困难症】

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                

     1.2、方法重写 overdide:

      在Java程序中,类的继承关系可以产生一个子类,子类继承父类,它具备了父类所有的特征,继承了父类所有的方法和变量。

      子类可以定义新的特征,当子类需要修改父类的一些方法进行扩展,增大功能,程序设计者常常把这样的一种操作方法称为重写或覆盖

    /**
    1>定义:在子类中重新定义父类中已有的方法
    
    2> “==”:具有相同的方法名称、参数列表。
    
    3> “<=”:返回值类型和声明异常类型,子类小于等于父类。
    
    4> “>=”:重写方法时,子类不能使用比父类中被覆盖的方法更严格的访问权限(便于实现多态),也就是说不能低于父类设置的访问权限。 */

               

    2、“==”和equals和hashCode有什么区别

      2.1    “==”:代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。

      2.2    equals:实际是上是Object类中定义的一个方法【public boolean equals(Object obj)】,提供定义 “对象内容相等” 的逻辑。一般都会重写equals方法。

      具体来说,如果两个变量是基本数据类型,可以(只能)直接使用==来比较其对应的值是否相等。

      (1)如果一个变量指向的数据是对象(引用类型),那么涉及到了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存(栈内存)。

               这时候如果用==表示:这两个对象是否指向同一个对象(即指向同一块存储空间——堆内存)。但是如果要比较这两个对象的内存(占内存)是否相等,==运算符就无法实现了。

      (2)在没有覆盖equals方法的情况下,equals方法与==运算符一样,比较的是引用。

        equals方法的特殊之处在于它可以被覆盖,通过覆盖的方法让它不是比较引用而是比较数据内容,例如String类的equals方法就是用于比较两个独立的对象的内容是否相同,即堆中的内容是否相同。

    public static void main(String[] args)
        {
            String s1=new String("hello");
            String s2=new String("hello");
            String s3=s1;
            System.out.println(s1==s2);   //false,说明只能比较堆内存中存储的值
            System.out.println(s1==s3);    //true
            System.out.println(s1.equals(s3));  //true
            System.out.println(s1.equals(s2));  //true
        }

      2.3     hashCode()方法:也是从Object类中继承过来的,也用来鉴定两个对象是否相等。

         Object类的hashCode方法返回:对象在内存中的地址转换成的一个int值,如果没有重写hashCode方法,任何对象的hashCode方法都是不相等的。

         (1)在HashMap中,由于key是不可以重复的,在判断key是否重复就使用了hashCode方法,并且也用到了equals方法,此处不可以重复指的是equals方法和hashCode方法只要有一个不等就可以了。

         (2)一般在覆盖equals方法的同时也要覆盖hashCode方法,否则就会违反Object hashCode的通用约定,从而导致该类无法无所有基于散列值的集合类(HashMap、HashSet和HashTable)结合在一起正常运行

    // 原因:
       (1)如果只覆盖了equals方法而没有覆盖hashCode方法,则两个不同的实例 A 和 B,虽然equals结果相等,但是却会有不同的‘HashCode,这样HashMap中会同时存在A和B,而实际上我们需要HashMap里面只能保存其中一个。
        比如你只覆盖了equals方法而没有覆盖hashCode方法,那么HashMap在第一步寻找链表的时候会出错,有同样值的两个对象Key1和Key2并不会指向同一个链表或桶,因为你没有提供自己的hashCode方法,那么就会使用Object的hashCode方法,
        该方法是根据内存地址来比较两个对象是否一致,由于Key1和Key2有不桶的内存地址,所以会指向不同的链表,这样HashMap会认为key2不存在,虽然我们期望Key1和Key2是同一个对象;
    (2)反之如果只覆盖了hashCode方法而没有覆盖equals方法,那么虽然第一步操作会使Key1和Key2找到同一个链表,但是由于equals没有覆盖,那么在遍历链表的元素时,key1.equals(key2)也会失败(事实上Object的equals方法也是比较内存地址),
    从而HashMap认为不存在Key2对象,这同样也是不正确的。

    3、super

       super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。

      (1)每个子类构造方法的第一条语句,都是隐含地调用super()。依次向上追溯每个父类,如果没有这种形式的构造函数,那么在编译的时候会报错。

          流程就是:先向上追溯到Object的构造方法 ,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。【静态初始化块调用顺序  同理

      (2)如果显式的写出super();语句,则必须保证该语句是第一条语句,否则会报错。

      (3)super();如果不写,则编译器会自动添加,所以此时如果父类没有无参的构造函数就会出错。

      (4)既可以显式写super();前提是父类必须有无参的构造函数;也可以显式写super(实参); 前提是父类必须有带参的构造函数。

      (5)调用父类的构造函数的语句必须借助于super, 不能直接写父类的类名。

                    

     4、封装——使用访问控制符实现

       (1)【高内聚、低耦合】:①类的内部操作细节  自己完成,不允许外部干涉;②仅暴漏少量的方法给外部使用,尽量方便外部调用。

      (2)

      (3)使用细节——类的属性的处理:

          1> 一般使用private访问权限

          2> 提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供属性的赋值与独取值操作(注意:Boolean变量的get方法是is 开头的)

          3> 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰

    5、多态

      (1)指的是同一个方法调用,由于对象不同可能会有不同的行为。现实生活中,同一个方法,具体实现会完全不同。 

       (2)多态的要点:

           ① 多态是方法的多态,不是属性的多态(多态与属性无关)。

           ② 多态的存在要有3个必要条件(继承 + 方法重写 + 父类引用指向子类对象

           ③ 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。

              

    public class TestPoly{            //多态必备:继承 + 方法重写 + 父类引用指向子类对象
        public static void main(String[] args) {
            Animal a = new Animal();
            AnimalCry(a);
            
            Dog d = new Dog();
            AnimalCry(d);            // 多态 <=> Animal a = new Dog();
            
            Animal c = new Cat();    // 自动向上转型
            AnimalCry(c);
            
    //        c.nianren();             出错,因为在编译器里认为c 是Animal型
            Cat c2 = (Cat)c;          //强制向下转型
            c2.nianren();
        }
        static void AnimalCry(Animal a) {       
            a.shout(); 
        }
    }
    
    class Animal{
        public void shout() {
            System.out.println("叫了一声");
        }
    }
    class Dog extends Animal{
        public void shout() {
            System.out.println("汪汪汪");
        }
    }
    class Cat extends Animal{
        public void shout() {
            System.out.println("喵喵喵");
        }
        public void nianren() {
            System.out.println("粘人的小猫咪");
        }
    }

    运行结果:

      叫了一声
      汪汪汪
      喵喵喵
      粘人的小猫咪

    6、final关键字的作用

      (1)修饰变量:被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。

      (2)修饰方法:该方法不可以被子类重写。但是可以被重载。

      (3)修饰类:修饰的类不能被继承。比如:Math、String等。

    7、抽象abstract —— 意义:为子类提供统一的、规范的模板,子类必须实现

      (1)有抽象方法的类只能定义为抽象类

      (2)抽象类不能实例化,即不能用new来实例化抽象类

      (3)抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用

      (4)抽象类只能被继承

      (5)抽象方法必须被子类实现

    8、接口 interface

      (1)接口就是规范,定义的是一组规则。 里边所有的方法都是抽象方法,全面专业的实现了:规范和具体实现的分离。

      (2)定义接口的详细说明:

        

      (3)要点

        

      (4)为什么需要接口?接口和抽象类的区别?

        

      (5)接口相关规则

        

    9、内部类  —— 将一个类定义置入另一个类定义中就叫作“内部类”  outer$inner.class 

       (1)内部类分类:

           成员内部类:静态内部类 + 非静态内部类

           (局部)方法内部类     

           匿名内部类

       (2)类中定义的内部类特点

                      

      (3)匿名内部类

          

    public class TestInner {
    
        public static void main(String[] args) {
    
            // 创建内部类对象
            Outer.Inner inner = new Outer().new Inner();
            inner.show();
        }
    
    }
    
    class Outer{
        private int age = 10;
        
        public void testOuter() {
            System.out.println("Outer.testOuter!");
        }
        
        class Inner{
            int age = 20;
            public void show() {
                int age = 30;
                System.out.println("外部类的成员变量age:"+Outer.this.age);
                System.out.println("内部类的成员变量age:"+this.age);
                System.out.println("局部变量age:"+age);    
                }
            }
    }
    
    //运行结果
    外部类的成员变量age:10
    内部类的成员变量age:20
    局部变量age:30

    10、String类 —— 不可变字符序列

    11、数组

       (1)相同类型数据的集合。

       (2)foreach循环:专门用于读取数组或集合中所有的元素,即对数组进行遍历。

     

     拓展:

    1、集合框架的线程安全性

    • A,Vector相当于一个线程安全的List
    • B,HashMap是非线程安全的,其对应的线程安全类是HashTable
    • C,Arraylist是非线程安全的,其对应的线程安全类是Vector
    • D,StringBuffer是线程安全的,相当于一个线程安全的StringBuilder
    • E,Properties实现了Map接口,是线程安全的

    2、基于分代的垃圾收集算法

      设计思路:把对象按照寿命长短来分组,分为年轻代和年老代,新创建的对象被分在年轻代,如果对象经过几次回收后仍然存活,那么再把这个对象划分到年老代。

             年老代的收集频率不像年轻代那么频繁,这样就减少了每次垃圾回收时所要扫描的对象的数量,从而提高了垃圾回收效率

      划分为若干个子堆,每个堆对应一个年龄代:

             

    // JVM将整个堆划分为Young区、Old区和Perm区,存放不同年龄的对象,这个三个区存放的对象有如下区别:
    
      Young区:又分为Eden区和两个Survivor区,其中所有新创建的对象都在Eden区,当Eden区满后会触发minor GC将Eden区仍然存活的对象复制到其中一个Survivor区中,
    另外一个Survivor区中的存活对象也复制到这个Survivor中,以保证始终有一个Survivor区是空的。   Old区:存放的是Young区的Survivor满后触发的minor GC后仍然存活的对象,当Eden区满后会将对象存放到Survivor区中,如果Survivor区仍然存不下这些对象,
    GC收集器会将这些对象直接存到Old区,如果在Survivor区中的对象足够老,也直接存放到Old区,如果Old区也满了,将会触发Full GC,回收整个堆内存。   Perm区:存放的主要是类的Class对象,Perm区的垃圾回收也是由Full GC触发的。

    3、finally块中的代码什么被执行?

      若try{}里面有一个return语句,finally块里的代码也是在return之前执行的。

      如果try-finally或者catch-finally中都有return,那么finally块中的return语句会覆盖别的return语句,最终返回到调用者的是finally中的return的值。

     4、运行时异常和普通异常区别

      Java提供了两种错误的异常类,分别为Error和Exception,且他们有共同的父类Throwable。

      Error表示程序在运行期间出现了非常严重的错误,并且错误是不可恢复的。例如OutMemoryError、ThreadDeath、方法调用栈溢出  等都属于错误。当这些异常发生时,JVM一般会选择将线程终止。

      Exception表示可恢复的异常,是编译器可以捕捉到的。它有两种类型:检查异常和运行时异常

    • 检查异常:最常见的IO异常和SQ异常,这种异常都发生在编译阶段,编译器强制程序去捕获此类型的异常,果没有try……catch也没有throws抛出,编译是通不过的。
    • 运行时异常:编译器没有强制对其进行捕获处理,如果不对这种异常进行处理,当出现这一种异常时,会有JVM处理,例如NullPointException空指针异常,ClassCastException类转换异常,ArrayIndexOutBoundsException数组越界异常,算术异常等。

    5、多线程同步的实现方法

      1、synchronize关键字

      在Java中,每个对象都与一个对象锁与之相关联,该锁表明对象在任何时候只允许被一个线程所拥有,当一个线程调用对象的一个synchronize代码时,需要先获取这个锁,然后去执行相应的代码,执行结束后吗,释放锁。

      2、wait方法与notify方法

      线程调用对象的wait方法,进入等待状态,释放对象锁,并且可以调用notify方法通知正在等待的其他的线程。

    public class WaitAndNotify
    {
        class TestWait extends Thread
        {
            public void run()
            {
                test("wait线程");
            }
        }
    
        class TestNotify extends Thread
        {
            public void run()
            {
                test("notify线程");
            }
        }
    
        public void exe()
        {
            TestWait tw = new TestWait();
    
            TestNotify tn = new TestNotify();
            tn.start();
            tw.start();
        }
    
        // 监视器
        public synchronized void test(String str)
        {
            for (int i = 0; i < 10; i++)
            {
                if (i == 5)
                {
                    try
                    {
                        wait();
                    } catch (InterruptedException e)
                    {
    
                        e.printStackTrace();
                    }
                } else
                {
                    notify();
                }
                System.out.println(str + "-------------" + i);
            }
        }
    
        public static void main(String[] args)
        {
            new WaitAndNotify().exe();
        }
    }
    test

      3、Lock

      Lock接口和它的一个实现类ReentrantLock(重入锁)

      lock(): 以阻塞的方式获取锁,即若获取到锁,立即返回,如果别的线程持有锁,当前线程等待,直到获取锁后返回。

      tryLock():  以非阻塞的方式获取锁,只是尝试性的去获取一下锁,如果获取到锁,返回true,否则返回false

    6、sleep方法与wait方法的区别

      sleep和wait均是使线程暂停执行的方法,区别在于:

      1、原理不同。sleep方法是Thread类的静态方法,是线程用来控制自身流程的,它会使线程暂停执行一段时间,而把执行机会让给其他线程,等到计时时间一到,此线程就会自动“苏醒”。wait方法是Object类的方法,用于线程间的通信,这个方法会使得拥有该对象锁的进程等待,直到其他线程调用notify方法时才醒来。

      2、对锁的处理机制不同。由于sleep方法的主要作用是让线程暂停执行一段时间,时间一到则自动恢复,不涉及线程间的通信,因此调用sleep方法不会释放锁。而调用wait方法后,线程会释放掉它所占用的锁,从而使线程所在对象中其他synchronize数据可被别的线程使用。

      3、使用区域不同。wait方法必须放在同步控制方法或同步语句块中使用,而sleep()可以在任何地方使用。

    7、synchronize与Lock区别

       1、用法不同。synchronize既可以加在方法上,也可以加载特定代码中,括号表示需要锁的对象。

                 Lock需要显示的指定起始位置和终止位置。synchronize是托管给JVM执行的,Lock的锁定是通过代码实现的。

       2、锁机制不一样。synchronize获取锁和释放锁的方式都在在块结构中,当获取多个锁时,必须以相反的顺序释放,并且是自动释放的。

                 Lock则需要开发人员手动去释放,并且必须在finally块中释放,否则会引起死锁问题的发生。

    8、join()方法的作用

      join方法的作用是:让调用该方法的线程在执行完run()方法后,再执行join方法后面的代码(插队)。例如可以通过线程A的join方法来等待线程A的结束。

    9、Http中get与post方法的区别

      get方法的作用主要用来获取服务器端资源信息,如同数据库中查询操作一样,不会影响到资源本身的状态。

           post方法提供了比get方法更加强大的功能,它除了能够从服务器端获取资源外,同时还可以向服务器上传数据

      -——  get方法主要用来从服务器上获取数据,也可以像服务器上传数据,但是不建议,原因如下:

      (1)采用get方法向服务器上传数据时,一般将数据添加到URL后面,并且二者用“”连接,各个变量之间用“&”连接。由于URL对长度的限制,此种方法能上传的数据量非常小。

          post方法传递数据通过http请求的附件进行的,传送的数据量更大。

      (2)get方法上传数据被彻底暴露在url中,本身存在安全隐患。

    10、Servlet中forward和redirect有什么区别

      1、forward是服务器内部的重定向(转发),服务器直接访问目标地址的url,把那个url的响应读取过来,而客户端并不知道。

       (1)在客户端浏览器的地址栏不会显示转向后的地址。

       (2)是一次请求,由于在整个定向的过程中用的是同一个Request,因此forward会将Request的信息带到被定向的jsp或Servlet中使用,资源可以共享。

       (3)不能访问外部服务器(站点)资源

      2、redirect是客户端的重定向,是完全的跳转,即客户端浏览器会获取到跳转后的地址,然后重新发送请求,比forward多一次网络请求。

          (1)在客户端浏览器的地址栏显示转向后的地址。

       (2)是两次请求,不能使用request对象共享资源。

       (3)可以访问其他服务器(站点)资源

            

    11、getparameter和getattribute的区别

    (1)作用范围

      request.getParameter()方法:传递的数据,会从Web客户端传到Web服务器端,代表HTTP请求数据,取得通过类似post,get等方式传入的数据(String类型)。

      request.setAttribute()和getAttribute()方法:传递的数据只会存在于Web容器内部,在具有转发关系的Web组件之间共享,仅仅是请求处理阶段。这两个方法能够设置Object类型的共享数据。

    (2)返回类型

    •  request.getAttribute()方法返回request、sessiont范围内存在的对象
    •    request.getParameter()方法是获取http提交过来的数据(String)

    12、JDK1.8中的ConcurrentHashMap

      与jdk1.7相比,jdk1.8中主要做了2方面的改进:

      改进一:取消segments字段,直接采用transient volatile HashEntry<K,V>[] table保存数据,采用table数组元素作为锁,从而实现了对每一行数据进行加锁,进一步减少并发冲突的概率。

      改进二:将原来table数组+单链表的数据结构,改为table数组+单链表+红黑树结构。

                          采用单链表方式,查询某个节点的时间复杂度为O(n),因此,对于个数超过8的列表,jdk1.8中采用了红黑树的结构,查询时间复杂度可以降低到O(logN)

      HashEntry 类的 value 域被声明为 Volatile 型,Java 的内存模型可以保证:某个写线程对 value 域的写入马上可以被后续的某个读线程“看”到。

      在 ConcurrentHashMap 中,不允许用 null作为键和值,当读线程读到某个 HashEntry 的 value 域的值为 null 时,便知道产生了冲突——发生了重排序现象( 对链表的结构性修改都可能会导致value为null 

            需要加锁后重新读入这个 value 值。这些特性互相配合,使得读线程即使在不加锁状态下,也能正确访问 ConcurrentHashMap。 

  • 相关阅读:
    springboot 无法访问静态资源
    webrtc源码阅读理解一
    c++ include的顺序重要吗?
    简说yuv
    i420 转 nv21
    ffmpeg mp4 转 yuv、 y4m转yuv、mp4转y4m && ffplay 播放y4m、yuv
    mysql 查询json字符串条件
    Webpack4.X中sourcemap的配置 详解
    webpack如何打包生成的map文件不生效?
    vue中使用setInterval,移入暂停,移出继续
  • 原文地址:https://www.cnblogs.com/timetellu/p/11340538.html
Copyright © 2011-2022 走看看