List集合

List接口簡(jiǎn)介

??List是Collection的子接口,其最大的特點(diǎn)是允許保存有重復(fù)元素?cái)?shù)據(jù),該接口的定義如下:

public interface List<E> extends Collection<E>

??但是需要清楚的是List子接口對(duì)于Collection接口進(jìn)行了方法擴(kuò)充。

  • 獲取指定索引上的數(shù)據(jù)E get?(int index)
  • 修改指定索引上的數(shù)據(jù):E set?(int index, E element)
  • 返回ListIterator接口對(duì)象:ListIterator<E> listIterator()

??但是List本身依然是一個(gè)接口,接口要想使用則一定要子類來(lái)完成定義夯到,在List子接口中有三個(gè)常用子類:ArrayList枣申、Vector售葡、LinkedList。

List子接口

??從JDK1.9開始忠藤,List接口中追加有一些static方法挟伙,以方便用戶的處理。
范例:觀察List的靜態(tài)方法

import java.util.Arrays;
import java.util.List;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        List<String> all = List.of("hello", "world", "你好", "MLDN", "餓了么模孩?");
        Object[] result = all.toArray();
        System.out.println(Arrays.toString(result));//[hello, world, 你好, MLDN, 餓了么尖阔?]
    }
}

這些操作方法并不是List的傳統(tǒng)用法,是在JDK1.9后添加的新功能榨咐。

ArrayList子類

??ArrayList是List子接口中使用最多的一個(gè)子類介却,但是這個(gè)子類在使用時(shí)也是有前提要求的,所以本次來(lái)對(duì)這個(gè)類的相關(guān)定義以及源代碼組成進(jìn)行分析块茁,在Java里面ArrayList類的定義如下:

public class ArrayList<E> extends AbstractList<E> mplements List<E>, RandomAccess, Cloneable, Serializable
ArrayList的繼承結(jié)構(gòu)

范例:使用ArrayList實(shí)例化List父接口

import java.util.ArrayList;
import java.util.List;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        List<String> all=new ArrayList();//為L(zhǎng)ist父接口進(jìn)行實(shí)例化
        all.add("hello");
        all.add("hello");//重復(fù)數(shù)據(jù)
        all.add("wolrd");
        all.add("MLDN");
        System.out.println(all);//[hello, hello, wolrd, MLDN]
    }
}

通過(guò)本程序可以發(fā)現(xiàn)List的存儲(chǔ)特征:

  • 保存的順序就是其存儲(chǔ)的順序齿坷;
  • List集合里面允許存在有重復(fù)數(shù)據(jù);

??在以上的程序中雖然實(shí)現(xiàn)了集合的輸出数焊,但是這種輸出的操作時(shí)直接利用了每一個(gè)類提供的toString()方法實(shí)現(xiàn)的永淌,為了方便的進(jìn)行輸出處理,在JDK1.8后Iterable定義有一個(gè)forEach方法佩耳,方法定義如下:

  • 輸出支持:default void forEach?(Consumer<? super T> action)

范例:利用forEach()方法進(jìn)行輸出(非標(biāo)準(zhǔn)輸出)

import java.util.ArrayList;
import java.util.List;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        List<String> all = new ArrayList();//為L(zhǎng)ist父接口進(jìn)行實(shí)例化
        all.add("hello");
        all.add("hello");//重復(fù)數(shù)據(jù)
        all.add("wolrd");
        all.add("MLDN");
        all.forEach((s -> {
            System.out.print(s + "仰禀、");
        }));
        //hello、hello蚕愤、wolrd答恶、MLDN饺蚊、
    }
}

需要注意的是,此種輸出并不是正常開發(fā)情況下要考慮的操作形式悬嗓。

范例:觀察List集合的其它操作方法

import java.util.ArrayList;
import java.util.List;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        List<String> all = new ArrayList();//為L(zhǎng)ist父接口進(jìn)行實(shí)例化
        System.out.printf("集合是否為空污呼?%s、集合元素個(gè)數(shù):%s\n",all.isEmpty(),all.size());//集合是否為空包竹?true燕酷、集合元素個(gè)數(shù):0    
        //集合是否為空?true周瞎、集合元素個(gè)數(shù):0
        all.add("hello");
        all.add("hello");//重復(fù)數(shù)據(jù)
        all.add("wolrd");
        all.add("MLDN");
        all.forEach((s -> {
            System.out.print(s + "苗缩、");
        }));
        //hello、hello声诸、wolrd酱讶、MLDN、
    }
}

??如果以方法的功能為例彼乌,那么ArrayList中操作支持與之前編寫的鏈表形式是非常相似的泻肯,但是它并不是使用鏈表來(lái)實(shí)現(xiàn)的,通過(guò)類名稱實(shí)際上就已經(jīng)可以清楚的發(fā)現(xiàn)了慰照,ArrayList應(yīng)該封裝的是一個(gè)數(shù)組灶挟。
ArrayList構(gòu)造:public ArrayList()

/**
 * JDK1.8:Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

ArrayList構(gòu)造:public ArrayList?(int initialCapacity)

transient Object[] elementData;
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
        }
    }

通過(guò)有參構(gòu)造方法可以發(fā)現(xiàn),在ArrayList中所包含的數(shù)據(jù)實(shí)際上就是一個(gè)對(duì)象數(shù)組毒租。在進(jìn)行數(shù)據(jù)追加時(shí)發(fā)現(xiàn)ArrayList集合中保存的對(duì)象數(shù)組長(zhǎng)度不夠時(shí)稚铣,那么會(huì)將會(huì)開辟新的數(shù)組,同時(shí)將原始的舊數(shù)組內(nèi)容拷貝到新數(shù)組中墅垮。
而后數(shù)組的開辟操作:

private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity <= 0) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return minCapacity;
    }
    return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity  : hugeCapacity(minCapacity);
}

??如果在實(shí)例化ArrayList類對(duì)象時(shí)沒有傳遞初始化額長(zhǎng)度惕医,則默認(rèn)情況下會(huì)使用空數(shù)組,但是如果在進(jìn)行數(shù)據(jù)增加時(shí)噩斟,發(fā)現(xiàn)數(shù)組容量不夠,則會(huì)判斷當(dāng)前的增長(zhǎng)容量與默認(rèn)的容量的大小孤个,使用較大的一個(gè)數(shù)值進(jìn)行新的數(shù)組開辟剃允,所以可以得出結(jié)論:
JDK1.7+:ArrayList默認(rèn)的構(gòu)造只會(huì)使用默認(rèn)的空數(shù)組,使用時(shí)才會(huì)開辟數(shù)組齐鲤,默認(rèn)的開辟長(zhǎng)度為10斥废,自動(dòng)增長(zhǎng)倍數(shù)為1.5倍:oldCapacity + (oldCapacity >> 1)

//JDK1.7
public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    this.elementData = new Object[initialCapacity];
}
public ArrayList() {
    super();
    this.elementData = EMPTY_ELEMENTDATA;
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

JDK1.6及以前:ArrayList默認(rèn)的構(gòu)造實(shí)際上就會(huì)默認(rèn)開辟大小為10的數(shù)組,自動(dòng)增長(zhǎng)倍數(shù)為(1.5倍+1):(oldCapacity * 3)/2 + 1

// ArrayList帶容量大小的構(gòu)造函數(shù)给郊。
public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
    // 新建一個(gè)數(shù)組
    this.elementData = new Object[initialCapacity];
}
// ArrayList構(gòu)造函數(shù)牡肉。默認(rèn)容量是10。
public ArrayList() {
    this(10);
}
public void ensureCapacity(int minCapacity) {
    //對(duì)于modCount變量淆九,我們后面會(huì)給出解釋
    modCount++;
    // 當(dāng)前數(shù)組的長(zhǎng)度
    int oldCapacity = elementData.length;
    // 最小需要的容量大于當(dāng)前數(shù)組的長(zhǎng)度則進(jìn)行擴(kuò)容
    if (minCapacity > oldCapacity) {
        Object oldData[] = elementData;
        // 新擴(kuò)容的數(shù)組長(zhǎng)度為舊容量的1.5倍+1
        int newCapacity = (oldCapacity * 3) / 2 + 1;
        // 如果新擴(kuò)容的數(shù)組長(zhǎng)度還是比最小需要的容量小统锤,則以最小需要的容量為長(zhǎng)度進(jìn)行擴(kuò)容
        if (newCapacity < minCapacity)
            newCapacity = minCapacity;
        // minCapacity is usually close to size, so this is a win:
        // 進(jìn)行數(shù)據(jù)拷貝毛俏,Arrays.copyOf底層實(shí)現(xiàn)是System.arrayCopy()
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
}

在JDK1.7+中,當(dāng)ArrayList之中保存的容量不足時(shí)會(huì)采用1.5倍的方式進(jìn)行增長(zhǎng)饲窿,原始長(zhǎng)度為0煌寇,擴(kuò)容:(0->10->15->22->33->49->73->……)

??ArrayList擴(kuò)容采用的是將原數(shù)組的內(nèi)容拷貝到擴(kuò)容后的新數(shù)組中逾雄,所以在使用ArrayList類或其子類時(shí)一定要估算實(shí)際存儲(chǔ)的數(shù)據(jù)量大小阀溶,一般采用有參構(gòu)造進(jìn)行創(chuàng)建,以避免ArrayList重復(fù)擴(kuò)容影響性能和產(chǎn)生過(guò)多的垃圾數(shù)組空間鸦泳。

ArrayList保存自定義類

??通過(guò)之前的分析已經(jīng)清楚了ArrayList子類的實(shí)現(xiàn)原理以及List核心操作银锻,但是在測(cè)試的時(shí)候使用的是系統(tǒng)提供的String類,這是一個(gè)設(shè)計(jì)比較完善的類做鹰,而對(duì)于類集而言也可以實(shí)現(xiàn)自定義類對(duì)象的保存击纬。
范例:實(shí)現(xiàn)自定義類對(duì)象保存

import java.util.ArrayList;
import java.util.List;
@lombok.Data//會(huì)自動(dòng)生成getter、setter誊垢、equals掉弛、hashCode、toString
@lombok.NoArgsConstructor//會(huì)自動(dòng)生成無(wú)參構(gòu)造
class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return String.format("姓名:%s喂走、年齡:%s", name, age);
    }
}
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        List<Person> all = new ArrayList();
        all.add(new Person("張三", 30));
        all.add(new Person("李四", 28));
        all.add(new Person("王五", 32));
        System.out.println(all.contains(new Person("王五", 32)));
        all.remove(new Person("王五", 32));
        all.forEach(System.out::println);//方法引用代替了消費(fèi)型的接口
        /**
         * true
         * 姓名:張三殃饿、年齡:30
         * 姓名:李四、年齡:28
         */
    }
}

在使用List保存自定義對(duì)象時(shí)芋肠,如果需要使用到contains()乎芳、remove()方法進(jìn)行查詢或刪除處理時(shí)一定要保證類中已經(jīng)覆寫了equals()方法。

LinkedLIst子類

??在List接口中還有一個(gè)比較常用的子類:LinkedList帖池,這個(gè)類通過(guò)名稱就可以發(fā)現(xiàn)其特點(diǎn):基于鏈表的實(shí)現(xiàn)奈惑。那么首先觀察一下LinkedList的定義:

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable
LinkedLIst類的繼承關(guān)系如下

范例:使用LinkedList實(shí)現(xiàn)集合操作

import java.util.LinkedList;
import java.util.List;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        List<String> all = new LinkedList<>();
        System.out.printf("集合是否為空?%s睡汹、集合元素個(gè)數(shù):%s\n",all.isEmpty(),all.size());
        all.add("hello");
        all.add("hello");
        all.add("wolrd");
        all.add("MLDN");
        all.forEach(System.out::println);
    }
}

??如果現(xiàn)在只是觀察程序的功能會(huì)發(fā)現(xiàn)和ArrayList使用時(shí)完全一樣的肴甸,但是其內(nèi)部實(shí)現(xiàn)機(jī)制是完全不同的,首先觀察LinkedList構(gòu)造方法中并沒有提供像ArrayList那樣的初始化大小的方法囚巴,而只是提供了無(wú)參構(gòu)造處理:“public LinkedList()”原在。隨后觀察add()方法的具體實(shí)現(xiàn)。

public boolean add(E e) {
    linkLast(e);
    return true;
}

在之前編寫自定義鏈表時(shí)彤叉,是判斷了傳入數(shù)據(jù)是否為null庶柿,如果為null則不進(jìn)行保存,但在LinkedList中并沒有做這樣的處理秽浇,而是所有的數(shù)據(jù)都可以保存,而后此方法調(diào)用了linkLast()方法(再最后一個(gè)節(jié)點(diǎn)后追加)浮庐。

void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

在LinkedList類中保存的數(shù)據(jù)都是利用Node節(jié)點(diǎn)進(jìn)行的封裝處理,同時(shí)為了提高程序執(zhí)行性能柬焕,每一次都會(huì)保存上一個(gè)追加的節(jié)點(diǎn)(最后一個(gè)節(jié)點(diǎn))审残,就可以在增加數(shù)據(jù)的時(shí)候避免遞歸處理梭域,在增加數(shù)據(jù)時(shí)要進(jìn)行數(shù)據(jù)保存?zhèn)€數(shù)的追加。

??通過(guò)上面的分析维苔,可以發(fā)現(xiàn)LinkedList封裝的就是一個(gè)鏈表實(shí)現(xiàn)碰辅。

Vector子類

??Vector是一個(gè)原始古老的程序類,這個(gè)類是在JDK1.0時(shí)提供的介时。到了JDk1.2時(shí)由于許多開發(fā)者已經(jīng)習(xí)慣于使用Vector没宾,并且許多系統(tǒng)類也是Vector實(shí)現(xiàn)的,考慮到請(qǐng)使用的廣泛性沸柔,所以類集框架將其保留了下來(lái)循衰,并讓其多實(shí)現(xiàn)了一個(gè)List接口,觀察Vector的結(jié)構(gòu)定義:

public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable

繼承結(jié)構(gòu)與ArrayList是相同的褐澎,所以來(lái)講這個(gè)類繼承結(jié)構(gòu)如下会钝。

Vector

范例:Vector類使用

import java.util.List;
import java.util.Vector;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        List<String> all = new Vector();
        System.out.printf("集合是否為空?%s工三、集合元素個(gè)數(shù):%s\n",all.isEmpty(),all.size());
        all.add("hello");
        all.add("hello");
        all.add("wolrd");
        all.add("MLDN");
        all.remove("hello");
        all.add(null);
        all.forEach(System.out::println);
    }
}

??下面可以進(jìn)一步的觀察Vector類實(shí)現(xiàn):

public Vector() {
    this(10);
}
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}
public Vector(int initialCapacity, int capacityIncrement) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    this.elementData = new Object[initialCapacity];
    this.capacityIncrement = capacityIncrement;
}

Vector類如果使用的是無(wú)參構(gòu)造方法迁酸,則一定會(huì)默認(rèn)開辟一個(gè)10個(gè)長(zhǎng)度的數(shù)組,而后其余的實(shí)現(xiàn)操作與ArrayList是相同的俭正。通過(guò)源代碼分析可以發(fā)現(xiàn)奸鬓,Vector類中的操作方法采用的都是synchronized同步處理,而ArrayList并沒有進(jìn)行同步處理掸读,所以Vector類中的方法在多線程訪問(wèn)的時(shí)候?qū)儆诰€程安全的串远,但是性能不如ArrayList高。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末儿惫,一起剝皮案震驚了整個(gè)濱河市澡罚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肾请,老刑警劉巖留搔,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铛铁,居然都是意外死亡隔显,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門避归,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)荣月,“玉大人管呵,你說(shuō)我怎么就攤上這事梳毙。” “怎么了捐下?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵账锹,是天一觀的道長(zhǎng)萌业。 經(jīng)常有香客問(wèn)我,道長(zhǎng)奸柬,這世上最難降的妖魔是什么生年? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮廓奕,結(jié)果婚禮上抱婉,老公的妹妹穿的比我還像新娘。我一直安慰自己桌粉,他們只是感情好蒸绩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著步藕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乞娄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼巨缘。 笑死搁骑,一個(gè)胖子當(dāng)著我的面吹牛煤率,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播昼捍,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鹃彻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼团赁!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起怀挠,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后裁赠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佩捞,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年琼富,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了薯鼠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狞贱,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布茬贵,位于F島的核電站解藻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏葡盗。R本人自食惡果不足惜螟左,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一啡浊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胶背,春花似錦巷嚣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至红且,卻和暖如春坝茎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暇番。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工嗤放, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人壁酬。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓次酌,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親舆乔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子和措,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 導(dǎo)航 前言 List 常見實(shí)現(xiàn)類 ArrayListArrayList類特點(diǎn)ArrayList解析ArrayLis...
    HikariCP閱讀 514評(píng)論 0 1
  • 前言 聲明,本文用得是jdk1.8 前一篇已經(jīng)講了Collection的總覽:Collection總覽蜕煌,介紹了一些...
    Java3y閱讀 1,641評(píng)論 0 25
  • ? 在編寫java程序中派阱,我們最常用的除了八種基本數(shù)據(jù)類型,String對(duì)象外還有一個(gè)集合類斜纪,在我們的的程序中到處...
    Java幫幫閱讀 1,421評(píng)論 0 6
  • 第一步:聽課贫母,并跟隨老師隨堂練習(xí) 用元書紙練習(xí) “雨”“墨?”。重點(diǎn)理解點(diǎn)的不同形態(tài)盒刚,不要糾結(jié)字整個(gè)寫的好不好腺劣。 ...
    鉆石島書法班主任閱讀 550評(píng)論 0 1
  • 沒見面, 已聞到了她的馨香因块, 這是她名字自帶的優(yōu)雅橘原。 ——江采漁 如詩(shī)中走來(lái) 清新涵韻 素雅美好 一起看一下這好聽...
    江采漁閱讀 2,369評(píng)論 0 1