Java基础重点知识

面向对象的三大特性是什么?

  • 继承
    继承就是子类继承父类的特征和行为,似的子类对象(实例)具有父类实例和方法,或子类从父类继承方法,使用、子类具有父类相同的行为。Java的继承是单继承。
  • 封装
    封装就是把同一类事物的属性和方法归到同一个类中,方便使用。 封装可以被认为一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。封装最主要的功能在于我们能修改自己的代码实现,而不弄修改那些调用我们代码的程序片段。
  • 多态
    多态是同一个行为具有多个不同表现形式或形态的能力。
    多态是同一个接口,使用不同的实例而执行不同的操作。产生的条件继承、重写、父类引用指向子类对象。

重载和重写有什么区别?

  • 重写(Override)
    重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变,即外壳不变,核心重写!
    重写的好处在于子类可以根据需要,定义特定于自己的行为,也就是说子类能够根据需要实现父类的方法。
  • 重载(Overload)
    重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
    每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
    最常用的地方就是构造器的重载。
    总结一下:
    (1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
    (2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
    (3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

多态的实现机制是什么?

封装和继承几乎都是为多态而准备的。
多态是同一个行为具有多个不同表现形式或形态的能力。
多态是同一个接口,使用不同的实例而执行不同操作。
多态是面向对象编程语言的重要特性,它允许基类的指针或引用指向派生类的对象,而在具体访问时实现方法的动态绑定。
多态存在的三个必要条件:
继承(核心)
重写
父类引用指向子类对象。

是否可以继承String类

不可以,String是final类型的,不能继承。

接口和抽象类的区别?

  • 共同点:
    都是上层的抽象层
    都不能被实例化
    都不能包含抽象方法,这些抽象的方法用于描述具备的功能
  • 区别
    • 在抽象类中可以写非抽象方法,从而避免砸子类中重复书写它们。这样可以提高代码的复用性,这是抽象类的优势接口中只能有抽象的方法
    • 一个类只能继承一个直接父类,这个父类可以是具体的类也可是抽象类,但是一个类可以实现多个接口,接口的设计具有更大的可扩展性,而抽象类设计必须十分谨慎。
      *抽象界别(从到到低)接口>抽象类>实现类
      *接口的设计目的,是对累的行为进行约束,侧重于动作,而抽象类的设计目的,是代码复用。

内部类的介绍

放在一个类的内部的类我们叫做内部类

  • 作用
  • 内部类可以很好的实现隐藏
  • 内部类拥有外部类的所有元素访问权限
  • 可以实现多重继承

equals()和==区别

*equals()和"=="操作用于对象的比较,检查两对象的相等性,但是他们的主要区别在于强者是方法,后者是操作符。

  • 一般使用==比较原生类型如:boolean、int、char等等,使用equals()比较对象
  • 一般使用==比较指向相同的对象 返回true,equals()的返回结果依赖于具体业务实现,一般重写equals方法时,同样重写hashcode方法,默认的equals方法实现是与""操作符一样的。
  • 字符串的对比使用equals()代替==操作符。

静态变量和实例变量的区别

解释:

  • 在语法定义上的区别:在静态变量前要加static关键字,二实例变量(成员变量)前则不加
    *在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会分配空间,才能使用这个实例变量。
    静态变量不属于某个实例对象,而是属于类,所以称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,只分配一次,静态变量就可以被使用了。总之,实例变量必须穿件对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

参考代码

public class VariantTest {
    public  static int staticVar=0;
    public int  instanceVar=0;

    public VariantTest() {

        staticVar++;
        instanceVar++;
        System.out.println("staticVar:"+staticVar+"--instanceVar:"+instanceVar);
    }
    public static  void  main(String [] args)
        {
           VariantTest var=new VariantTest();

            VariantTest var1=new VariantTest();

            VariantTest var2=new VariantTest();

            VariantTest va3=new VariantTest();

            VariantTest var4=new VariantTest();

            VariantTest va5=new VariantTest();
        }
}
// 结果
/*
staticVar:1--instanceVar:1
        staticVar:2--instanceVar:1
        staticVar:3--instanceVar:1
        staticVar:4--instanceVar:1
        staticVar:5--instanceVar:1
        staticVar:6--instanceVar:1
*/


Integer与int的区别

解释

  • Integer是int提供的分装类,从java5开始引入了自动封装/拆箱机制,是的二中可以相互转换。而int是java的基本数据类型。
  • Integer默认值是null,而int默认值是0
  • Integer是对象,用一个引用指向这个对象,而int是基本类型,直接存储数值。
  • Integer提供了好多鱼整数相关的操作方法,例如,讲一个字符串转换成整数等。

代码

public static  void  main(String [] args)
    {
      int i=128;
      Integer i2=128;
      Integer i3=new Integer(128);
      System.out.println(i==i2); //Integer会自动拆箱为int,所以为true
      System.out.println(i==i3);//true

        Integer i4=127;
        Integer i5=127;
        System.out.println(i4==i5);//true

        /*
        * -128 and 127 (inclusive) as required by JLS
        * Integer缓存换位是-128到127
        * */
        Integer i6=128;
        Integer i7=128;
        System.out.println(i6==i7);//false


       /*
       * i5 从缓存中直接返回
       * i8 new了一个新对象
         * */
        Integer i8=new Integer(127);
        System.out.println(i5==i8);//false

        /*
        * new了两个新对象
        * */
        Integer i9=new Integer(128);
        Integer i10=new Integer(128);
        System.out.println(i9==i10); //false



    }

String,StringBuilder,StringBuffer

解释:

  • 执行速度,StringBuilder>StringBuffer>String
    String最慢的原因
    String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可改变的,但后者的对象时变量,是可以改变的。
  • 线程安全
    在线程安全上, StringBuilder是线程不安全的,而StringBuffer是线程安全的。(StringBuffer中很多方法带有synchronized关键字)

总结

String: 适用于少量字符串操作。
StringBuilder:适用于单线程下载字符缓冲区进行大量的操作情况。
StringBuffer:适用多线程下在字符缓冲区进行大量的操作的情况。

代码

 public static  void  main(String [] args)
     {

        String s1="233";
        s1=s1+"www";
        System.out.println(s1);

        StringBuilder sbd=new StringBuilder();
        sbd.append("StringBuilder").append("12").append("23").append(56);
        System.out.println("StringBuilder:"+sbd.toString());

        StringBuffer sbf=new StringBuffer();
        sbf.append("StringBuffer").append("12").append("34").append("56");

        System.out.println("StringBuffer:"+sbf.toString());

        StringBuilder sb=new StringBuilder("1111122222");
        StringBuffer sbffer=new StringBuffer("3333344444");

         // 下面是验证线程安全的测试
         // 循环创建多个线程,测试StringBuilder
        for (int i=0;i<=100;i++)
        {
            new Thread(new MyThread(sb)).start();

        }
         // 循环创建多个线程,测试StringBuffer
         for (int i = 0; i < 100; i++) {
             new Thread(new MyThreadSbf(sbffer)).start();
         }



     }
 private static class MyThread implements Runnable {
     // 定义成员属性
     private StringBuilder sb;

     // 构造函数,参数初始化
     private MyThread(StringBuilder sb) {
         this.sb = sb;
     }

     public void run() {
         // 循环可以增加出现线程不安全的情况
         for (int i = 0; i < 100; i++) {
             sb.reverse();
         }
         // 输出sb字符串(默认调用了toString())
         System.out.println(sb);
     }
 }
 private static class MyThreadSbf implements Runnable {
     // 定义成员属性
     private StringBuffer sb;

     // 构造函数,参数初始化
     private MyThreadSbf(StringBuffer sb) {
         this.sb = sb;
     }

     public void run() {
         // 循环可以增加出现线程不安全的情况发生
         for (int i = 0; i < 100; i++) {
             sb.reverse();
         }
         // 输出sb字符串(默认调用了toString())
         System.out.println(sb);
     }
 }
 
 
 /*
 * 2121111212
   2121111212
   3333344444
  3333344444
  4444433333
 3333344444
3333344444

 * */

java程序初始化的顺序是什么样的.

  • 静态对象(变量)优先于非静态对象(变量)初始化,其中静态对象(变量)只初始化一次,而非静态对象(变量)可能会初始化多次。
  • 父类优先于子类进行初始化
  • 按照成员变量的定义顺序进行初始化。即使变量定义散布于方法中,它们依然在任何方法(包括构造函数)被调用前先初始化。
    总结:
    父类静态字段初始化
    父类静态代码块
    子类静态字段初始化
    子类静态代码块初始化
    父类普通字段初始化
    父类构造代码块
    父类构造函数
    子类普通字段初始化
    子类构造代码块
    子类构造函数
    static字段、代码块的执行顺序优先于非static字段、代码块。这是因为在静态域是属于类的,在类加载后就一直存在:而普通类需要创建对象才能访问。而在创建对象时,需要先加载父类,然后再加载子类,因此父类的静态字段初始化和静态代码块执行先于子类。
// 测试Java程序初始化的顺序
public class CodeBlockTest {
    public static void main(String[] args) {
        Child child = new Child();
    }
}

class Father {
    public static String fatherStr1 = "fatherStr1(静态字段初始化值)";

    public String fatherStr2 = "fatherStr2(字段初始化值)";
    static {
        System.out.println("父类静态代码块:" + fatherStr1 +",静态变量已经初始化");
        fatherStr1 = "fatherStr1(静态代码块赋值)";
    }
    {
        System.out.println("父类构造代码块fatherStr1:" + fatherStr1);
        System.out.println("父类构造代码块fatherStr2:" + fatherStr2);
        fatherStr2 = "fatherStr2(构造代码块赋值)";
    }

    public Father() {
        System.out.println("父类构造函数:" + fatherStr2);
        fatherStr2 = "fatherStr2(构造函数赋值)";
    }
}

class Child extends Father {
    public static String childStr1 = "childStr1(静态字段初始化值)";
    public String childStr2 = "childStr2(字段初始化值)";
    static {
        System.out.println("子类静态代码块:" + childStr1 + ",静态变量已经初始化");
        childStr1 = "childStr1(静态代码块赋值)";
    }
    {
        System.out.println("子类构造代码块childStr1:" + childStr1);
        System.out.println("子类构造代码块childStr2:" + childStr2);
        childStr2 = "childStr2(构造代码块赋值)";
    }

    public Child() {
        System.out.println("子类构造函数:" + childStr2);
        childStr2 = "childStr2(构造函数赋值)";
    }
}
/*父类静态代码块:fatherStr1(静态字段初始化值),静态变量已经初始化
子类静态代码块:childStr1(静态字段初始化值),静态变量已经初始化
父类构造代码块fatherStr1:fatherStr1(静态代码块赋值)
父类构造代码块fatherStr2:fatherStr2(字段初始化值)
父类构造函数:fatherStr2(构造代码块赋值)
子类构造代码块childStr1:childStr1(静态代码块赋值)
子类构造代码块childStr2:childStr2(字段初始化值)
子类构造函数:childStr2(构造代码块赋值)*/

Class.forName和classloader区别

  • 相同点:
    java中class.forName() 和classLoader都可用来对类进行加载
  • 不同点:
    Class.forName除了该类的.class 文件加载到jvm中之外,还会对类进行解释,执行类中的static块
    而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块
    Class.forName(name,initialize,loader)带参函数也可以控制是否加载static块。并且只有调用了newInstace()方法采用调用构造函数,来创建累的对象。

Collection和Collections有什么区别

  • java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口。Collection接口在Java类库中有很多的具体实现。Collection接口的意义是为各种具体的集合提供最大化的统一操作形式。
  • List、set、Queue接口都继承Collection。直接实现该接口的类只有AbstractCollection类,该类也只有一个抽象类,提供了对集合类操作的一些基本实现。List和Set的具体实现类基本上都直接或间接的继承了该类。
    java.util.Collections是一个包装类,它包含有各种集合操作的静态方法(对结合搜索、排序、线程安全化等)大多数方法都是用来处理线性表的。此类不能实例化,可以把Collections是一个工具类。

List和Set,map有什么区别?List,Set,Map是否继承自Collection接口?

List

  • 可以允许重复的对象
  • 可以插入多个null值
  • 是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
  • 常用的实现类有ArrayList、LinkedList和Vector。ArrayList最为流行,它提供了使用索引的任意访问,而LinkedList则对于经常需要从List中添加或者删除元素的场合更为合适。

Set

  • 不允许重复对象
  • 无序容器,你无法保证每个元素的存储顺序。ThreeSet通过Comparator或者Comparable维护了一个排序顺序。
  • 只允许一个null元素
  • Set接口最流行的几个实现类是HashSet、LinkedHashSet以及TreeSet

Map

  • Map不是collection的子接口或者实现类。Map是一个接口。
  • Map的每个Entry都保持有两个对象,也就是一个键一个值,Map不是。
  • TreeMap也通过Comparator或者Comparable维护了一个排序顺序。
  • Map里你可以拥有随意个null值但最多只能有一个null键。
  • Map接口最流行的几个实现类是HashMap、LinkedHashMap、和TreeMap(HashMap、TreeMap最常用)。

List,Set,Map是否继承自Collection接口?

List、set是继承自Collection接口,Map不是。

代码

public interface List<E> extends Collection<E> 
public interface Set<E> extends Collection<E>
public interface Map<K,V>

public static  void  main(String [] args)
    {
        List<java.lang.String> list=new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("D");
        list.add(null);
        list.add(null);
        System.out.println("list:"+list);

        Set<String>set=new HashSet<>();
        set.add("A");
        set.add("B");
        set.add("C");
        set.add("D");
        set.add("A");
        set.add("null");
        set.add("null");
        System.out.println("set:"+set);

        Map<String,String> map=new HashMap<>();
        map.put("A","A");
        map.put("A","B");
        map.put("B","C");
        map.put("C","D");

        System.out.println("map:"+map);

    }
/* list:[A, B, C, D, D, null, null]
 set:[A, B, C, D, null]
 map:{A=B, B=C, C=D}*/

ArrayList和LinkList有何区别?

  • ArrayList是实现了基础动态数组的数据结构,而LinkedList是基于链表的数据结构
  • 对于随机访问的get和set,ArrayList优先于LinkedList,因为LinkedList要移动指针
  • 对于添加和删除操作的add和remove,一般大家都会说LinkedList要比ArrayList快,因为ArrayList要移动数据。

ArrayList中的元素如何删除?

  • 使用iterator(迭代器)
public static  void  main(String [] args)
    {

        List<String> list=new ArrayList<>();
        list.add("北京");
        list.add("上海");
        list.add("重庆");
        list.add("广东");
        list.add("重庆");
        list.add("广东");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext())
        {
            String item=iterator.next();
            if(item.equals("广东"))
            {
                iterator.remove();
            }
        }
        System.out.println(list);
    }

iterator和listIterator的区别

  • listIterator 继承自iterator
  • listIterator比iterator强大,listIterator提供了很多iterator没有的方法.如(add、nextIndex()、set、hasPrevious等)
public static  void  main(String [] args)
    {
        List<String> list=new ArrayList<>();
        list.add("beijing");
        list.add("shanghai");
        list.add("guangzhou");
        list.add("tangshan");
        Iterator<String> it = list.iterator();
        while (it.hasNext())
        {
            String item=it.next();
            if(item.equals("shanghai"))
            {
                it.remove();
            }
        }
        System.out.println(it);

      Iterator<String> it2= list.iterator();
      while (it2.hasNext())
      {
          System.out.println("Iterator:"+it2.next());
      }


        List<String> list2=new ArrayList<>();
        list2.add("beijing");
        list2.add("shanghai");
        list2.add("guangzhou");
        list2.add("tangshan");
        ListIterator<String> stringListIterator = list2.listIterator();
        String first=stringListIterator.next();
        System.out.println("first:"+first);
        stringListIterator.add("香港");
        //遍历list方法1:
        System.out.println("遍历list方法1");
        for (String str:list2)
        {
            System.out.println(str);
        }
        //遍历list方法2:
        System.out.println("遍历list方法2");
        while (stringListIterator.hasNext())
        {
            System.out.println("下一个元素索引:"+stringListIterator.nextIndex());
            System.out.println("下一个元素:"+stringListIterator.next());
        }

    }

Comparable和Comparator接口有什么区别?

相同点

Comparable和Comparator都是用来实现集合中元素的比较、排序的。

不同点

  • 接口定义的方法不同
    Comparable接口里面的方法是public int compareTo(T o),在java.lang包下
    Comparator接口里面的方法是 int compare(T O1,T O2) 在java.util包下
  • Comparable是在集合内部定义的方法实现排序,Comparator是在集合外部实现的排序。
  • Comparator比Comparable 要灵活
    Comparable
final  int STUDENT_NUM=4;
Student[] allStudents=new Student[STUDENT_NUM];

allStudents[0]=new Student("0001","a");
allStudents[1]=new Student("0002","b");
allStudents[2]=new Student("0004","d");
allStudents[3]=new Student("0003","c");
for (int i=0;i<allStudents.length;i++)
{
    allStudents[i].setAge(i*10);
    allStudents[i].setScore(99-i*1.5);
}

Arrays.sort(allStudents);
System.out.println("学号"+"\t姓名"+"\t年龄"+"\t成绩");
for (int i=0;i<allStudents.length;i++)
{
    System.out.println(allStudents[i]);
}


    public Student(String ID, String name, Integer age, Double score) {
        this.ID = ID;
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getID() {
        return ID;
    }

    public void setID(String ID) {
        this.ID = ID;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    @Override
    public int compareTo(Student o) {
        return  this.ID.compareTo(o.ID);
    }

    @Override public String toString() {
        return "Student{" + "ID='" + ID + '\'' + ", name='" + name + '\'' + ", age=" + age + ", score=" + score + '}';
    }
}

Comparator

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

            final  int STUDENT_NUM=4;
            Student[] allStudents=new Student[STUDENT_NUM];

            allStudents[0]=new Student("0001","a");
            allStudents[1]=new Student("0002","b");
            allStudents[2]=new Student("0004","d");
            allStudents[3]=new Student("0003","c");
            for (int i=0;i<allStudents.length;i++)
            {
                allStudents[i].setAge(i*10);
                allStudents[i].setScore(99-i*1.5);
            }
            System.out.println("按姓名进行降序");
            Arrays.sort(allStudents,new ComparatorWithNameDown());
            for (int i = 0; i < allStudents.length; i++) {
                System.out.print(allStudents[i]);
            }
            System.out.println();
            System.out.println("按姓名进行升序");
            Arrays.sort(allStudents,new ComparatorWithOrder());
            for (int i = 0; i < allStudents.length; i++) {
                System.out.print(allStudents[i]);
            }
            System.out.println();
            System.out.println("分数进行升序");
            Arrays.sort(allStudents,new ComparatorWithScoreUp());
            for (int i = 0; i < allStudents.length; i++) {
                System.out.print(allStudents[i]);
            }
            System.out.println();
            System.out.println("按分数进行降序");
            Arrays.sort(allStudents,new ComparatorWithScoreDown());
            for (int i = 0; i < allStudents.length; i++) {
                System.out.print(allStudents[i]);
            }
        }
}

public class ComparatorWithOrder implements Comparator<Student> {

    // 按姓名进行升序排序
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getName().compareTo(o2.getName());
    }

}
// 按姓名进行倒叙排序
class  ComparatorWithNameDown implements Comparator<Student>
{

    @Override
    public int compare(Student o1, Student o2) {
        return o2.getName().compareTo(o1.getName());
    }
}
// 按分数进行降序排序
class  ComparatorWithScoreDown implements Comparator<Student>
{

    @Override
    public int compare(Student o1, Student o2) {
        return o2.getScore().compareTo(o1.getScore());
    }
}
// 按分数进行升序排序
class  ComparatorWithScoreUp implements Comparator<Student>
{

    @Override
    public int compare(Student o1, Student o2) {
        return o1.getScore().compareTo(o2.getScore());
    }
}

posted @ 2019-01-09 17:23  小朋友写代码  阅读(102)  评论(0编辑  收藏  举报