Chapter. 10 泛型

10.1 泛型程序设计

泛型,指可以在类或方法中预支地使用未知的类型。泛型程序设计(Generic programming),意味着编写的代码可被很多不同类型的对象所重用。使用泛型机制编写的程序代码,要比那些杂乱使用Object变量然后再进行强制类型转换的代码具有更好的安全性可读性。泛型对于集合类尤其有用,如集合类ArrayList

10.1.1 引入

在Java SE5.0之前,Java泛型程序设计是用继承实现的。例如ArrayList类只维护一个Object引用的数组:

public class JustTest{ //before Java SE 5.0
public Object get(int i){...}
public void add(Object o){...}
...
private Object[] elementData;
}

如此实现有两个问题,当获取一个值时必须将返回的Object类进行强制类型转换。

ArrayList files = new ArrayList();
...
String filename = (String) names.get(0);

此外,下面这里不存在错误检查,可向数组列表中添加任何类的对象

files.add(new File("..."));

10.1.2 使用泛型的好处

泛型为上面所产生的问题提供了一个更好的解决方案——类型参数type parameters)。其带来的好处:

  1. 代码具有更好的可读性。

    ArrayList<String> files = new ArrayList<String>(); //一看便知道该数组列表中包含的是String对象
  2. 编译器能够很好地利用信息,无需进行强制类型转换。

    String filename = files.get(0); //当调用get()无需强转,编译器便知道返回值类型为String,而不是Object
    String str = it.next(); //使用迭代器无需强转

    一般在创建对象时,将未知的类型确定具体类型。若没有指定泛型,则默认类型为Object类。

  3. 编译器可以进行检查,避免插入错误类型的对象。将运行时的ClassCastException转移到了编译时异常。

    files.add("abcd"); //Correct
    //files.add(5); 当集合明确类型后存放类型不一致就会编译报错!

    泛型,是数据类型的一部分。我们将类名与泛型合并一起看做数据类型。

10.2 泛型的定义与使用

TIPS:类型变量 使用大写形式且比较短。在Java库中,使用变量E表示集合的元素类型KV分别表示表的关键字与值的类型T表示任意类型

10.2.1 含有泛型的类

定义格式为:修饰符 class 类名<代表泛型的变量>{ }

class ArrayList<E>{ //API中的ArrayList集合
public boolean add(E e){ ... }
public E get(int index){ ... }
...
}
public class MyGenericClass<MVP>{ //自定义的泛型类
private MVP mvp;
public void setMVP(MVP mvp){
this.mvp = mvp;
}
public MVP getMVP(){
return mvp;
}
}
public class Pair<T, U> { ... } //泛型类可以有多个类型变量,此处的Pair类第一个域和第二个域使用不同的类型

创建对象时,就需要将泛型确定下来。即用具体的类型替换类型变量就可以实例化泛型类型,例如:

ArrayList<Integer> list = new ArrayList<Integer>(); //在对象list中,所有的E类型都替换为String类型
MyGenericClass<String> a = new MyGenericClass<String>();
String mvp = a.getMVP();
MyGenericClass<Integer> b = new MyGenericClass<Integer>();
Integer mvp2 = b.getMVP();

10.2.2 含有泛型的方法

泛型方法可以定义在普通类中,也可以定义在泛型类中。

定义格式为:修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }

public class MyGenericMethod{
public <T> void show(T mvp){
System.out.println(mvp.getClass());
}
public <T> T show2(T mvp){
return mvp;
}
}

调用泛型方法时,大多情况下方法调用可以省略<…>具体的类型参数,编译器有足够的信息能够推断出所调用的方法。

String middle = Array.show2(names);

10.2.3 含有泛型的接口

定义格式为:修饰符 interface 接口名<代表泛型的变量> { }

public interface MyGenericInterface<E>{
public abstract void add(E e);
public abstract E getE();
}

使用方式:

  1. 定义实现类时即确定泛型的类型。

    public class MyImp1 implements MyGenericInterface<String>{
    @Override
    public void add(String e){ //方法参数从类型参数改为String
    //...
    }
    public String getE(){ //返回类型从类型参数改为String
    //...
    }
    }
  2. 始终不确定泛型的类型,直至创建对象时才确定泛型的类型。

    public class MyImp2 implements MyGenericInterface<E>{
    @Override
    public void add(E e){
    //...
    }
    public E getE(){
    //...
    }
    }

    确定泛型:

    MyImp2<String> my = new MyImp2<String>();
    my.add("2333");

10.3 泛型通配符

10.3.1 通配符的基本使用

当使用泛型类或者接口时,传递的数据中泛型类型不确定,可以通过<?>表示,其中?表示未知通配符。但一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用;只能接受数据,而不能往该集合中存储数据。

public class JustTest {
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<Integer>();
getElement(list1);
Collection<String> list2 = new ArrayList<String>();
getElement(list2);
}
public static void getElement(Collection<?> coll){
//....
}
}

TIPS:泛型不存在继承关系,如:Collection<Object> list = new ArrayList<String>(); 这种是错误写法!

10.3.2 通配符限定

Java的泛型可以指定一个泛型的上限或下限。

  • 泛型的上限

    格式:类型名称 <? extends 类> 对象名称

    意义:只能接收指定类型或其子类。

    public static void getElements1(Collection<? extends Number> coll){ ... }
    //此时的泛型 ? ,必须是Number类型或者Number类型的子类
  • 泛型的下限

    格式:类型名称 <? super 类> 对象名称

    意义:只能接收指定类型或其父类。

10.4 泛型的约束与局限性

  1. 不能用基本类型实例化类型参数。

    比如说,没有Pair<double>,而只有Pair<Double>。其原因在于类型擦除,Pair类含有Object类型的域,而Object不能存储double

  2. 运行时类型查询只适用于原始类型

    if(a instanceof Pair<String>){ /*...*/ } //true,实际上仅仅测试a是否为任意类型的Pair
    if(a instanceof Pair<T>) { /*...*/ } //true Pair<String> a = ...;
    Pair<Employee> b = ...;
    if(a.getClass() == b.getClass()){ /*...*/ } //比较结果为true,因为两次调用getClass都将返回Pair.class Pair<String> p = (Pair<String>) a; //WARNING---can only test that a is a Pair
  3. 不能抛出也不能捕获泛型类实例

    事实上,泛型类拓展Throwable都不合法。

    public class MyProblem<T> extends Exception{ /*...*/ } //不会通过编译,Error!

    不能再catch子句中使用类型变量,如下不能通过编译。

    public static <T extends Throwable> void doWork(Class<T> t){
    try {
    /*do work*/
    }
    catch (T e){ //ERROR--can't catch type variable!!!
    //...
    }
    }

    但在异常声明中可以使用类型变量,如下是合法的

    public static <T extends Throwable> void doWork(Class<T> t) throws T{
    try {
    /*do work*/
    }
    catch (T e){ //ERROR--can't catch type variable!!!
    //...
    }
    }
  4. 参数化类型的数组不合法。

    Pair<String> table = new Pair<String>[10]; //ERROR
    //若需要收集参数化类型的对象,最好使用ArrayList
    ArrayList<Pair<String>> table = ....
  5. 不能实例化类型变量。

    不能使用像new T(...)new T[...]或者T.class这样的表达式中的类型变量。

  6. 泛型类的静态上下文中类型变量无效。

  7. 注意擦除后的冲突。

Chapter 11. 集合

11.1 集合概述

从Java SE 5.0 开始,集合类是带有类型参数的泛型类。Java集合类库将接口实现分离。其集合按照其存储结构可分为两大类:单列集合java.util.Collection、双列集合Java.util.Map

实现 Collection 接口的类

集合类型 描述
\(ArrayList\) 动态增长和缩减的索引序列
\(LinkedList\) 可在任何位置进行高效插入和删除有序序列
\(ArrayDeque\) 循环数组实现的双端队列
\(HashSet\) 无重复元素且无序 的散列集
\(TreeSet\) 有序
\(LinkedHashSet\) 可记住元素插入次序的 集(链表+散列表实现)
\(PriorityQueue\) 高效删除最小元素的机会
\(BitSet\)(遗留) 存放序列的位集(功能同C++的位集模板)

实现 Map 接口的类

集合类型 描述
\(HashMap\) 存储键-值关联的数据结构
\(TreeMap\) 键值有序排列的映射
\(LinkedHashMap\) 可记住键-值添加次序映射

11.2 Collection 接口 与 Collections 工具类

11.2.1 Collection 继承结构

Collection接口,为单列集合类的根接口,用于存储一系列符合某种规则的元素。

它有两个重要子接口:java.util.Listjava.util.Set

  • List 特点为元素是有序的(指存储和取出元素的顺序是一致的)、且允许存储重复元素、有索引(故可用普通for循环进行遍历),它的主要实现类为java.util.ArrayListjava.util.LinkedList

  • Set 特点为元素不一定有序、不允许存储重复元素、没有索引(故不能用普通的for循环进行遍历),它的主要实现类为java.util.HashSetjava.util.TreeSet

11.2.2 Collection 常用方法

Collection中定义了单列集合(ListSet)通用的方法:

  • public boolean add(E element):将对象element添加至当前集合中。

    Collection<String> coll = new ArrayList<String>();
    coll.add("Luffy");
  • public void clear():清空集合中所有的元素。

  • public boolean remove(E element):在当前集合中删除对象element

  • public boolean contains(E element):判断当前集合中是否包含对象element

  • public boolean isEmpty():判断当前集合是否为空。

  • public int size():返回集合中元素的个数。

  • public Object[] toArray():将集合中元素,存储至数组中。

    Object[] arr = coll.toArray();
    for(int i = 0; i < arr.length(); i++){
    System.out.println(arr[i] + " ");
    }

11.2.3 Collections 工具类

java.utils.Collections是集合工具类,用于对集合进行相关操作。常用方法有:

  • public static <T> boolean addAll(Collection<T> c, T... elements)

    往集合c中添加多个相同类型的元素elements

    ArrayList<Integer> mylist = new ArrayList<Integer>();
    Collections.addAll(mylist, 233, 666, 1, 2);
    /* 上语句等价于下面写法
    mylist.add(233);
    mylist.add(666);
    mylist.add(1);
    mylist.add(2);
    */
  • public static void shuffle(List<?> list): 使用默认随机源对列表进行置换,所有置换发生的可能性都是大致相等的。(简而言之,打乱集合顺序)

    List<Integer> mylist = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) mylist.add(i);
    for(int i = 1; i <= 6; i++){
    System.out.println("第" + i + "次洗牌:");
    Collections.shuffle(mylist);
    System.out.println(mylist);
    }
  • public static<T> void sort(List<T> list):将集合中元素按照默认规则排序。

    public static<T> void sort(List<T> list, Comparator<? super T>):将集合中元素按照指定规则排序。

11.2.4 Comparator 比较器

Java中提供两种对象间比较大小的实现方式:

  • 采用java.lang.Comparable接口实现——强行对实现它的每个类的对象进行整体排序。(类的自然排序)

    有些标准的Java平台类,实现了Comparable接口,而该接口定义了compareTo方法。

    public interface Comparable<T>{
    int compareTo(T others);
    }

    而对于自定义的对象,必须通过实现Comparable接口自定义排列顺序,因为在Object类中没有提供任何compareTo接口的默认实现。如下展示了如何用“部件编号”为Item对象进行排序。实现Comparable接口的对象列表(和数组)可以通过Collections.sortArrays.sort进行排序。

    class Item implements Comparable<Item>{
    public int compareTo(Item other){
    return partNum - other.partNum; //若第一项位于第二项前面,则返回负值;编号相同返回0;否则返回正值。
    }
    }

    显然对于上面的Comparable接口定义排序有其局限性,对于一个给定的类,只能够实现这个接口一次(也就说只能在类中实现compareTo()一次)。如上例子,如果我希望在一个集合中按“部件编号”排序,在另一集合按描述信息排序,同时这个类创建者又没有实现Comparable接口,此时就需要下面的Comparator接口。

  • java.util.Comparator接口实现——强行对某个对象进行整体排序。

    Comparator接口声明了一个带两个显式参数compare方法。

    public interface Comparator<T>{
    int compare(T a, T b);
    }

    该接口代表一个比较器。这个比较器没有任何数据,只是比较方法的持有器,可以将Comparator传递给sort方法(如Collections.sortArrays.sort),或者传递给某些数据结构(如TreeSet)。

    SortedSet<Item> sortByDescription = new TreeSet<Item>(new Comparator<Item>(){
    @Override
    public int compare(Item a, Item b){
    String descrA = a.getDescription(); String descrB = a.getDescription();
    return descrA.compareTo(descrB);
    }
    }); //将Comparator对象传递给TreeSet构造器来告诉树集使用不同的比较方法
    Collections.sort(list, new Comparator<Student>(){
    @Override
    public int compare(Student a, Student b){
    return a.getAge() - b.getAge();
    }
    });

11.3 Iterator 接口与迭代器

11.3.1 概述

JDK专门提供一个接口java.util.Iterator,用于遍历集合中的元素。Iterator接口属于Java集合,但与CollectionMap这两个专门用于存储元素的接口不同,Iterator 主要用于迭代访问(即遍历)元素,因而,Iterator对象被称为迭代器。

使用迭代器时,元素被访问的顺序取决于集合类型。若对ArrayList进行迭代,迭代器会从索引0开始每迭代一次便+1;若访问HashSet中元素,每个元素将按照某种随机的次序出现(尽管该迭代过程一定能遍历到集合所有元素,但却无法预知元素被访问的次序)。

11.3.2 相关方法

Collection 接口拓展了Iterable接口,获取迭代器的方法为:

  • public Iterator<E> iterator():返回一个实现了Iterator接口的对象,可以使用该迭代器对象依次访问集合中的元素。

Iterator接口包含以下常用方法:

  • public E next():调用next时,迭代器会越过下一个元素,并返回刚刚越过的那个元素的的引用。当到达集合末尾时next方法会抛出NoSuchElementException

  • public boolean hasNext() :如果迭代器对象还有多个供访问的元素,返回true。反之返回false

    public class JustTest {
    public static void main(String[] args) {
    Collection<String> arr = new ArrayList<String>();
    arr.add("Luffy");
    arr.add("Nami");
    arr.add("Zoro");
    Iterator<String> it = arr.iterator();
    while(it.hasNext()){
    String tmp = it.next();
    System.out.println(tmp);
    }
    }
    }
  • public void remove() :删除上次调用next方法时返回的元素。(也就说,想要删除指定位置上的元素,仍然需要越过该元素)。当调用remove之前没有调用next是不合法的,抛出IllegalStateException异常

    Iterator<String> it = c.iterator();
    it.next(); //越过第一个元素
    it.remove(); //将刚越过的元素删去

应该将Java迭代器认为是位于两个元素之间的。C++标准模板库中迭代器是根据数组索引建模的,不需查找元素即可将迭代器向前移动一个位置。而Java不同,查找操作与位置变更紧密相连,查找一个元素的唯一方法是调用next,而在执行查找操作同时迭代器位置随之向前移动。

11.3.3 for each 循环

编译器将for each循环翻译为带有迭代器的循环,故使用for each循环遍历时,不能对集合元素进行增删操作。

for(元素的数据类型 变量名 : Collection集合或者数组){
//do something
}
public class JustTest {
public static void main(String[] args) {
Collection<String> arr = new ArrayList<String>();
arr.add("Luffy");
arr.add("Nami");
arr.add("Zoro");
for(String tmp: arr){
System.out.println(tmp);
}
}
}

11.4 List 接口与其子类

List 作为 Collection 集合的子接口之一,它用于描述一个有序集合,并且集合中每个元素的位置十分重要。它有两种访问元素的协议:使用迭代器,或用 getset 方法随机地访问每个元素(不适用链表,适用数组)。

11.4.1 数组列表(ArrayList )

java.util.ArrayList 封装了一个动态再分配的对象数组。元素增删慢,查找快。

ArrayList 方法不是同步的,故建议在不需要同步时使用ArrayList,比使用Vector更高效。

11.4.2 链表(LinkedList)

链表将每个对象存放在独立的节点中,每个节点还存放着序列中下一个节点的引用。而在Java中,所有链表实际上都是双向链表doubly linked)的。而java.util.LinkedList集合数据存储的结构即为双向链表,元素增删块,查找慢。

以下为LinkedList常用方法的举例使用:

import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator; public class LinkedListTest {
public static void main(String[] args) {
List<String> staff = new LinkedList<String>();
//调用LinkedList的add方法:将对象添加至链表尾部
staff.add("Luffy");
staff.add("Zoro");
staff.add("Sanji"); //遍历LinkedList
ListIterator<String> iter_1 = staff.listIterator();
while(iter_1.hasNext()){
String tmp = iter_1.next();
System.out.println(tmp);
} ListIterator<String> iter_2 = staff.listIterator();
//越过第一个元素,并返回该元素至oldName
String oldName = iter_2.next();
//调用ListIterator的Set方法,用一新元素取代调用next或previous方法返回的上一个元素
iter_2.set("Monkey.D.Luffy");
//调用子接口ListIterator的previous方法,返回越过的对象 if(iter_2.hasPrevious()) iter_2.previous();
//调用子接口ListIterator的add方法(注意区分上面的Collection的add方法),将对象添加至迭代器位置之前
iter_2.add("Nami");
}
}

由于迭代器是描述集合中位置的,故这种依赖位置的add方法将由迭代器负责,只有对自然有序的集合使用迭代器添加元素才有实际意义。

11.5 Set 接口与其子类

Set 作为 Collection 集合的子接口之一,它由散列表所实现,由于散列将元素分散在表的各个位置上,故其Set接口中元素是无序的(TreeSet 除外),并以某种规则保证存入元素是不重复的。

11.5.1 基于散列表的集(HashSet)

如果想要查看某个指定的元素,但不在意元素的顺序,散列表(hash Table)正能够满足于此。在散列表中,具有不同数据域的对象产生了不同的散列码hash code)。

HashSet类,正实现了基于散列表的集。它根据对象的散列码来确定元素在集合中的存储位置,它保证元素唯一性的方式依赖于hashCode方法与equals方法。由此,在用HashSet存放自定义类型元素时,需要覆写对象中的hashCode方法(没覆写的话每个新对象的hashCode值均不同)和equals方法(没覆写的话就是比较地址值),建立自己的比较方式方能保证HashSet集合中的对象唯一。

hashCode值是由操作系统产生的逻辑地址值,而地址值才是真实的物理地址。

/* Student.java文件中 */
public class Student{
private String name;
private int age; public Student(){
}
public Student(String name, int age){
this.name = name; this.age = age;
} public String getName(){ return name; }
public void setName(String name){ this.name = name; }
public int getAge(){ return age; }
public void setAge(int age){ this.age = age; } @Override
public boolean equals(Object o){ //覆写equals方法
if(this == o) return true;
if(o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, name);
}
@Override
public int hashCode(){ //覆写hashCode方法
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
} /* 测试类 HashSetTest.java */
public class HashSetTest{
public static void main(String[] args){
HashSet<Student> MySchool = new HashSet<Student>();
MySchool.add(new Student("Luffy", 18));
MySchool.add(new Student("Nami", 23));
MySchool.add(new Student("Luffy", 18));
for(Student peo : MySchool){
System.out.println(peo);
}
}
}
/* 运行结果 */
Student{name='Nami', age=23}
Student{name='Luffy', age=18}

11.5.2 树集(TreeSet)

TreeSet类与散列集十分类似,但它比`散列集有所改进。树集是一个有序集合(sorted collection),它可以以任意顺序将元素插入到集合中,当在对集合进行遍历时,每个值将自动地按照排序后的顺序呈现,(其中,排序是利用红黑树去完成的,每次将一个元素添加至树中时,都被放置在正确的排序位置上)故迭代器总以排好序的顺序去访问每个元素。

默认情况下,树集假定插入元素实现了Comparable接口(若元素为自定义对象,则需实现Comparable接口自定义排序)。对于基本类型的包装类和String默认为升序。

总而言之,将一个元素添加到TreeSet中要比添加到HashSet中会慢一些,不过TreeSet可自动对元素进行排序。

public class TreeSetTest {
public static void main(String[] args) {
Set myset = new TreeSet();
myset.add(233);
myset.add(666);
myset.add(1);
myset.add(42);
myset.add(233);
for(Iterator iter = myset.iterator(); iter.hasNext();){
System.out.println(iter.next());
}
}
}

11.6 Map 接口

集(set)是一个集合,可以快速查找现有元素,但要查看一个元素,需要查找元素的精确副本,但这并不是非常通用的查找方式。

通常,我们知道某些键的信息,并想要查找与之对应的元素,映射表(map)数据结构就是为此实现的。映射表用来存放键/值对,若提供了键,就能查到值。

Java类库为映射表提供两个通用实现:

  • HashMap :散列映射表,对键进行散列。
  • TreeMap :树映射表用键的整体顺序对元素进行排序。

尽管HashTable已被取代,但其子类Properties仍未退出历史舞台,在I/O流章节中会专门讲述。

键必须是唯一的,不能对同一个键存放两个值,每个键只能对应一个值。

注意:

  1. 使用HashMap存放自定义对象时,要保证对象唯一,必须覆写对象的hashCodeequals方法。
  2. 若希望保证map存放的key和取出的顺序一致,可使用java.util.LinkedHashMap集合来存放。

11.6.3 Map常用方法

  • public V put(K key, V value):将指定的键key与值value添加至Map集合中。若指定的键key在该集合中没有,则将指定的键值添加到集合中,并返回null;若指定的键key在集合中存在,则返回值为集合中键对应的值(指替换前的值),并将指定键所对应的值替换为指定的新值value
  • public V remove(Object key):将 指定的键key 所对应的 键值对元素 在Map集合中删除,同时返回被删除元素的 值 。
  • public V get(Object key):在Map集合中获取 指定的键key 所对应的值。
  • public Set<K> keySet():获取Map集合中所有的 键 ,存储到Set集合中。注意,keySet既不是HashSet也不是TreeSet
  • public Set<Map.Entry<K, V>> entrySet():获取Map集合中所有的键值对对象的Set集合。

11.6.2 Map的遍历方式

一、键找值方式

获取Map中所有键,由于键是唯一的,利用keySet方法得到一个存储所有键的Set集合,再遍历该Set集合的每一个键,根据键调用get()方法来获取键所对应的值。

HashMap<Integer, String> mymap = new HashMap<Integer, String>();
mymap.put(20190301, "Luffy");
mymap.put(20190304, "Nami");
mymap.put(20190302, "Zoro");
Set<Integer> mykeys = mymap.keySet();
for(int curkey: mykeys){
String curname = mymap.get(curkey);
System.out.println(curkey + "所对应的学生姓名为:" + curname);
}

二、键值对方式

Map中的keyvalue是一一对应的关系,而每一个键值对又称为Map中的一个Entry),Entry 将键值对的对应关系封装为对象,称为键值对对象,或称为 条目

在遍历Map集合时,就可从每一键值对Entry对象中获取对应的键与值。对于Entry,也提供了相应的方法:

  • public K getKey():获取Entry对象中的键。
  • public V getValue():获取Entry对象中的值。
  • public Set<Map.Entry<K, V>> entrySet():获取Map集合中所有的键值对对象的集合。
HashMap<Integer, String> mymap = new HashMap<Integer, String>();
mymap.put(20190301, "Luffy");
mymap.put(20190304, "Nami");
mymap.put(20190302, "Zoro");
Set<Map.Entry<Integer, String>> mySet = mymap.entrySet();
for(Map.Entry<Integer, String> a : mySet){
System.out.println(a.getValue() + "的学号为:" + a.getKey());
}

JavaSE 学习笔记05丨泛型、集合的更多相关文章

  1. JavaSE 学习笔记02丨对象与类

    Chapter 4. 对象与类 4.1 面向对象程序设计概述 面向对象程序设计(简称OOP),是当今主流程序设计范型.面向对象的程序是由对象组成的,每个对象(来自于标准库或自定义的)包含对用户公开的特 ...

  2. JavaSE 学习笔记01丨开发前言与环境搭建、基础语法

    本蒟蒻学习过C/C++的语法,故在学习Java的过程中,会关注于C++与Java的区别.开发前言部分,看了苏星河教程中的操作步骤.而后,主要阅读了<Java核心技术 卷1 基础知识>(第8 ...

  3. JavaSE学习笔记05面向对象编程01

    面向对象编程01 java的核心思想就是OOP 面向过程&面向对象 面向过程思想: 步骤清晰简单,第一步做什么,第二步做什么...... 面向过程适合处理一些较为简单的问题 面向对象思想: 物 ...

  4. JavaSE 学习笔记07丨IO流

    Chapter 13. IO流 13.1 File类 java.io.File类是文件(file)和目录(文件夹)(directory)路径名(path)的抽象表示,主要用于文件和目录的创建.查找和删 ...

  5. Linux 学习笔记05丨在Ubuntu 20.04配置FTP服务器

    感谢 linuxconfig.org 上的这篇英文教程 FTP用于访问和传输本地网络上的文件,通过安装 VSFTPD 软件,打开热点,配置相关信息后即能够启动并运行FTP服务器了. 1. 安装和配置V ...

  6. JavaSE 学习笔记08丨网络编程

    Chapter 14. 网络编程 14.1 计算机网络入门 当前节的知识点只是一个概述,更具体.详细的内容放在 计算机网络 中. 14.1.1 软件结构 C/S结构(Client/Server结构): ...

  7. JavaSE 学习笔记06丨并发

    Chapter 12. 并发 12.1 并发与并行 并发:指两个或多个事件在同一个时间段内发生. 并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,并发指的是在一段时间内宏观上有多个程 ...

  8. JavaSE 学习笔记04丨异常

    Chapter 9 异常 异常:指程序在执行过程中,出现的非正常的情况,最终导致JVM非正常停止. 在Java等面向对象的编程语言中,异常是一个类,所有异常都是发生在运行阶段的(因为也只有程序运行阶段 ...

  9. JavaSE 学习笔记03丨继承、接口、多态、内部类

    Chapter. 5 继承 继承作为面向对象的三大特征之一,它是多态的前提.它主要解决的问题是共性抽取. Java中的继承,是单继承.多级继承的. 已存在的类,被称为超类.基类.父类(parent c ...

随机推荐

  1. E. Tree Queries 解析(思維、LCA)

    Codeforce 1328 E. Tree Queries 解析(思維.LCA) 今天我們來看看CF1328E 題目連結 題目 給你一棵樹,並且給你\(m\le2e5\)個詢問(包含\(k\)個點) ...

  2. String字符串性能优化的探究

    一.背景 String 对象是我们使用最频繁的一个对象类型,但它的性能问题却是最容易被忽略的.String 对象作为 Java 语言中重要的数据类型,是内存中占用空间最大的一个对象,高效地使用字符串, ...

  3. Setuptools 【Python工具包详解】

    什么是setuptools setuptools是Python distutils增强版的集合,它可以帮助我们更简单的创建和分发Python包,尤其是拥有依赖关系的.用户在使用setuptools创建 ...

  4. 执行 vue inspect > output.js 报错,无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\vue.ps1,因为在此系统中禁止执行脚本

    无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\vue.ps1,因为在此系统中禁止执行脚本.有关详细信息,请参阅 "get-help ab ...

  5. Spring MVC json配置

    接口类的Controller,一般返回的是json数据,而Spring MVC中默认返回的string,而jsp页面的话,会按配置中自己行匹配转义字符串为对应的jsp文件. @Controller @ ...

  6. eclipse之SSH配置hibernate【三】

    配置hibernate,没有和spring整合,可以看成独立的部分. 在src下创建hibernate配置文件,hibernate.cfg.xml.主要是sql连接相关配置. <?xml ver ...

  7. JVM详解(二)-- 第2章 类加载器子系统

    一.JVM内存结构 1.1 内存结构---概略图 1.2 内存结构--详细图 二.类加载器子系统的作用 类加载器子系统负责从文件系统或网络中加载.Class文件,文件需要有特定的标识(cafe bab ...

  8. AC 自动机刷题记录

    目录 简介 第一题 第二题 第三题 第四题 第五题 第六题 简介 这就是用来记录我对于<信息学奥赛一本通 · 提高篇>一书中的习题的刷题记录以及学习笔记. 一般分专题来写(全部写一起可能要 ...

  9. .netcore使用autofac

    .netcore3.1使用autofac (.netcore中本身已经实现了IOC容器,其实没有必要替换成autofac.如果非常习惯autofac,替换也是无可厚非的.) 第一步.在项目中引入Aut ...

  10. 3.5 MyLinkedList 实现

    3.5 MyLinkedList 类的实现 MyLinkedList 将用双链表实现,并且还需要保留该表两端的引用.这将需要三个类 MyLinkedList 类,包含到两端的链.表的大小以及一些方法. ...