乐趣区

Java基础知识整理

面向对象和面向过程的区别

面向过程
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源; 比如单片机、嵌入式开发、Linux/Unix 等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展

面向对象
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低

获取用键盘输入常用的的两种方法

  1. 通过 Scanner

    Scanner input = new Scanner(System.in);
    String s  = input.nextLine();
    input.close();
  2. 通过 BufferedReader

    BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 
    String s = input.readLine(); 

Java 面向对象编程三大特性: 封装 继承 多态

封装
把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。

继承
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。

  1. 子类拥有父类非 private 的属性和方法。
  2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
  3. 子类可以用自己的方式实现父类的方法。

多态
指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
在 Java 中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。

重载和重写的区别

方法重载是指同一个类中的多个方法具有相同的名字, 但这些方法具有不同的参数列表, 即参数的数量或参数类型不能完全相同
(相同名字,不同参数)

方法重写是存在子父类之间的, 子类定义的方法与父类中的方法具有相同的方法名字, 相同的参数表和相同的返回类型
(相同名字,相同类型)(继承)

为什么函数不能根据返回类型来区分重载

因为调用时不能指定类型信息
如:

float max(int a,int b)
int max(int a,int b)

当调用 max(1,2)时,无法确定

抽象类(abstract)和接口(interface)

选择使用接口和抽象类的依据 抽象类 是对最本质的抽象,接口 是对动作的抽象
如:男人、女人是两个类,那可以抽象出一个类,人;人可以吃东西,学习等等,这些行为就是一个个接口

抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被 synchronized?

都不能。抽象方法需要子类重写,而静态的方法是无法被重写的;本地方式是由本地代码实现的方法,而抽象方法是没有实现的;synchronized 和方法的实现细节有关,抽象方法不涉及实现细节,因此都不能。

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

静态变量:被 static 修饰的变量,也称为类的变量,属于类,不属于类的任何一个对象,一个类不管创建多少对象,静态变量在内存只有一个拷贝,可以实现让多个对象共享内存
实例变量:必须依存某一实例,需要创建对象才能通过对象去访问它。

String、StringBuffer、StringBulider

  1. String 是引用类型,底层由 char 数组实现
  2. String:字符串常量,在修改时布改变自身,修改等于重新生成新的自符串对象;

StringBuffer:在修改时会改变对象自身,每次操作都是对 StringBuffer 对象本身进行修改,不是生成新的对象,使用场景是:对字符串经常改变情况下,主要方法:append()

  1. 线程安全:

String:定义对象后不可变,线程安全
StringBuffer:线程安全,对调用的方法加入同步锁,执行效率较慢,适用于多线程下操作字符串缓冲区大量数据
StringBuilderer:线程不安全,适用于单线程下操作字符串缓冲区大量数据

  1. 当我们使用 ”+” 时,编译器转换成了 StringBuilder,所以不要在 for 语句内使用;同时尽量不要 ”+” 和 StringBuilder 一起使用

对于三者使用的总结
操作少量的数据 String
单线程操作字符串缓冲区下操作大量数据 StringBuilder
多线程操作字符串缓冲区下操作大量数据 StringBuffer

一个类的构造方法的作用是什么 若一个类没有声明构造方法, 该程序能正确执行吗 ? 为什么?

主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。

== 与 equals(重要)

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。。(基本数据类型比较的是值,引用数据类型比较的是内存地址)
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况 1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况 2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

public class test1 {public static void main(String[] args) {String a = new String("ab"); // a 为一个引用

        String b = new String("ab"); // b 为另一个引用, 对象的内容一样

        String aa = "ab"; // 放在常量池中

        String bb = "ab"; // 从常量池中查找

        if (aa == bb) // true

            System.out.println("aa==bb");

        if (a == b) // false,非同一对象

            System.out.println("a==b");

        if (a.equals(b)) // true

            System.out.println("a.equals(b)");

        if (42 == 42.0) { // true

            System.out.println("true");

        }

    }

}

说明

  • String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。
  • 当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

hashCode 与 equals (重要)

  1. 如果两个对象相等,则 hashcode 一定也是相同的
  2. 两个对象相等, 对两个对象分别调用 equals 方法都返回 true
  3. 两个对象有相同的 hashcode 值,它们也不一定是相等的
  4. 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

length,length(),size()三者的区别

  • length 属性: 用于获取数组长度
int ar[] = new int{1,2,3}
/**
* 数组用 length 属性取得长度
*/
int lenAr = ar.length;// 此处 lenAr=3
System.out.println("Arr length:"+lenAr);
  • length()方法:用于获取字符串长度
String str = "Hello World Java";

/**
* 字符串用 length()方法取得长度
*/

int lenStr = str.length();// 此处 lenStr=16
System.out.println("Str length():"+lenStr);
  • size()方法:用于获取泛型集合有多少个元素
/**
* Collection 是整个类集之中单值保存的最大父接口,所以使用时需要用具体子类实例化
*/
Collection<String> col = new ArrayList<String>();
col.add("Hello");
col.add("World");
col.add("Java");
/**
* 类集框架用 size()方法取元素个数
*/
int sizeCol = col.size();// 此处 sizeCol=3
System.out.println("Col size:"+sizeCol);

List 的三个子类的特点

  • ArrayList 底层是数组,查询快,增删慢
  • LinkedList 底层是链表,增删快,查询慢
  • voctor 底层是数组,线程安全,增删慢,查询慢

如何实现数组和 List 之间的转换

List 转换成为数组:调用 ArrayList 的 toArray 方法。
数组转换成为 List:调用 Arrays 的 asList 方法。

两个队列模拟一个堆栈,队列是先进先出的,堆栈是先进后出的

思路:队列 a 和 b

  入栈:a 队列为空,b 为空,将“a,b,c,d,e”先放入 a 中,a 进栈为“a,b,c,d,e”出栈:将 a 队列依次加入 ArrayList 集合 c 中,以倒序的方法,将 c 中的集合取出,放入 b 中,再将 b 队列出列
  
 public static void main(String[] args) {Queue<String> a = new LinkedList<>();
        Queue<String> b = new LinkedList<>();
        List<String> c = new ArrayList<>();

        a.offer("a");
        a.offer("b");
        a.offer("c");
        a.offer("d");
        a.offer("e");
        System.out.print("进栈:");
        for(String s:a){c.add(s);
            System.out.print(s);
        }

        for(int i=c.size()-1;i>=0;i--){b.offer(c.get(i));
        }

        System.out.println();
        System.out.print("出栈:");
        for(String s:b){System.out.print(s);
        }
    }

队列 offer,add 区别

一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。
这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。

poll,remove 区别:

remove() 和 poll() 方法都是从队列中删除第一个元素。remove() 的行为与 Collection 接口的版本相似,但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。

peek,element 区别:

element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时,element() 抛出一个异常,而 peek() 返回 null。

HashMap 和 HashTable 的区别

  • HashMap 是线程不安全的,是 Map 的一个子接口,是将键映射到值的对象,不允许键值重复,允许空键和空值,由于非线程安全,HashMap 的效率要较 HashTable 高
  • HashTable 是线程安全的一个集合,不允许 null 作为一个 key 或者 value 值,是线程安全的

异常处理

在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。
Throwable:有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。
Error(错误): 是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题
Exception(异常): 是程序本身可以处理的异常

  • RuntimeException。RuntimeException 异常由 Java 虚拟机抛出。
  • NullPointerException(要访问的变量没有引用任何对象时,抛出该异常)
  • ArithmeticException(算术运算异常,一个整数除以 0 时,抛出该异常)
  • ArrayIndexOutOfBoundsException(下标越界异常)。
  • SQLException,SQL 异常,一般都是 SQL 语句错误

==异常和错误的区别:异常能被程序本身可以处理,错误是无法处理==

throw 和 throws 区别

  • throw:
    throw 在方法体内,表示抛出异常,执行 throw 一定是抛出了某种异常
  • throws:
    throws 跟在方法声明的后面,表示可能出现某种异常

try 和 finally 的返回值

  1. 如果 try 有返回值,就把返回值保存到局部变量中;
  2. 执行 jsr 指令跳到 finally 语句里执行;
  3. 执行完 finally 语句后,返回之前保存在局部变量表里的值。
  4. 如果 try,finally 语句里均有 return,忽略 try 的 return,而使用 finally 的 return

迭代器 Iterator

迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
使用:

  1. 使用方法 iterator()要求容器返回一个 Iterator。第一次调用 Iterator 的 next()方法时,它返回序列的第一个元素。注意:iterator()方法是 java.lang.Iterable 接口, 被 Collection 继承。
  2. 使用 next()获得序列中的下一个元素。
  3. 使用 hasNext()检查序列中是否还有元素。
  4. 使用 remove()将迭代器新返回的元素删除。
退出移动版