Java进阶-Java学习路线课程第二课:Java集合框架-HashSet的使用及去重原理

本博客地址 | GitHub | 更多资源免费下载

        小伙伴们,大家早上好!今天我给大家带来Java集合框架Collection之Set集合讲解,今天主要讲解Set集合接口下的实现类HashSet集合,今天的讲解重要,请大家仔细看噢!

Java集合框架-HashSet的使用及去重原理

     前面我们已经学过了List集合(不熟悉List集合的小伙伴点击:Java进阶-Java学习路线课程第一课:Java集合框架-ArrayList和LinkedList的使用),相信大家对List集合有所了解了吧!List集合是有索引,有序和不唯一,那Set集合有什么特征呢?当然有它的特征,没有索引,无序和唯一。下面我们来一一讲讲,当然,重点会讲一下HashSet去重。

文章目录

1、首先,还是让大家看看一个简洁的Java集合框架结构体系图:
2、看看这些接口和类有什么特征。
  • Collection(接口)

特征(单列集合): 不唯一,无序

  • List(子接口)

特征(单列集合): 不唯一,有序

  • Set(子接口)

特征(单列集合): 唯一,无序

  • Map(接口)

特征(双列集合): 键值对

key --->value  map.put("userName",uName);
key是拿的Set的特性,而value是拿的Collection的特性。
  • HashSet

特征:底层由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。无索引,唯一,无序。最大的优势就是去重。

3、先给大家演示一下HashSet去重代码,能做到去重吗?代码如下:
News.java  实例类
package com.javaxyz.entity;

/**
 * @ClassName:News.java
 * @Description:新闻实例类
 * @Author:DongGaoYun
 * @AuthorEnglishName:Andy
 * @URL:www.javaxyz.com 或 www.gyun.org
 * @Email:DongGaoYun@qq.com
 * @QQ:1050968899
 * @WeiXin:QingYunJiao
 * @WeiXinGongZhongHao: JavaForum
 * @Date:2019-10-22 下午2:23:38
 * @Version:1.0 完成以下基本代码:  1.属性  2.get和set方法   3.构造方法  4.toString
 * 说明
   1.这个新闻实例类没有重写equals和hashCode方法
   2.没有用泛型,后面章节会介绍  
 */
public class News {
	//属性
	private int id;
	private String title;//标题
	private String author;//作者

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * @return the title
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * @param title
	 *            the title to set
	 */
	public void setTitle(String title) {
		this.title = title;
	}

	/**
	 * @return the author
	 */
	public String getAuthor() {
		return author;
	}

	/**
	 * @param author
	 *            the author to set
	 */
	public void setAuthor(String author) {
		this.author = author;
	}

	// toString
	@Override
	public String toString() {
		return "News [id=" + id + "," + " title=" + title + "," + " author="
				+ author + "]\n";
	}

	/**
	 * 无参构造方法
	 */
	public News() {
	}

	/**
	 * 有参构造方法
	 * @param id
	 * @param title
	 * @param author
	 */
	public News(int id, String title, String author) {
		super();
		this.id = id;
		this.title = title;
		this.author = author;
	}

}
4、测试代码:
package com.javaxyz.test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.junit.Test;

import com.javaxyz.equals.News;

/**
 * @ClassName:HashSetDemo.java
 * @Description:Set的运用 
 * @Author:DongGaoYun
 * @AuthorEnglishName:Andy
 * @URL:www.javaxyz.com 或 www.gyun.org
 * @Email:DongGaoYun@qq.com
 * @QQ:1050968899
 * @WeiXin:QingYunJiao
 * @WeiXinGongZhongHao: JavaForum
 * @Date:2019-10-25 
 * @Version:1.0 HashSet 优势: 去重 特有功能:
 * 
 */
public class HashSetDemo1 {
	// 需求:
	// 增加新闻元素
	// 获取新闻总数
	// 操作HashSet容器,移除元素
	// 判断是否包含此元素
	// 打印输出四种方式
	
    //忽略警告
	@SuppressWarnings("all")
	// public static void main(String[] args) {
	@Test
	public void testSet() {

		// 创建对象
		// 创建多态的形式,要注意的点:只能调用父类与子类重写的方法,子类特有方法无法调用
		Set list = new HashSet();// 多态的形式。//1.父子关系 2.重写方法 3.父类的引用指向子类对象

		News news1 = new News(1, "张卓1", "green1");
		News news2 = new News(2, "张卓2", "green2");
		News news11 = new News(2, "张卓2", "green2");
		News news3 = new News(3, "张卓3", "green3");
		News news4 = new News(4, "张卓4", "green4");
		News news5 = new News(5, "张卓5", "green5");
		News news6 = new News(6, "张卓6", "green6");
		News news7 = new News(7, "张卓7", "green7");
		News news8 = new News(8, "张卓8", "green8");
		// 插入数据
		list.add(news1);
		list.add(news2);
		list.add(news3);
		// 注意set是无序的,没有索引,所以报错
		// list.add(1,news4);
		// 插入数据
		list.add(news6);
		list.add(news11);
		// 总条数
		System.out.println(list.size());

		// 操作HashSet容器,移除元素
		/*
		 * list.remove(0); list.remove(news1);
		 */
		// 判断是否包含此元素
		System.out.println(list.contains(news7));
		// list
		System.out.println("-------第一种打印输出方法---start----");
		System.out.print(list);
		System.out.println("-------第一种打印输出方法---end----");
		System.out.println();
		//System.out.println("-------第二种打印输出方法-普通for--start----");
		// 普通for不能用

		/*
		 * for (int i = 0; i < list.size(); i++) { News newss = (News)
		 * list.get(i); System.out.println("News [id=" + newss.getId() + "," +
		 * " title=" + newss.getTitle() + "," + " author=" + newss.getAuthor() +
		 * "]"); }
		 */

		//System.out.println("-------第二种打印输出方法---end----");
		System.out.println();
		System.out.println("-------第二种打印输出方法-增强for--start----");
		for (Object object : list) {
			News newss = (News) object;
			System.out.println("News [id=" + newss.getId() + "," + " title="
					+ newss.getTitle() + "," + " author=" + newss.getAuthor()
					+ "]");
		}
		System.out.println("-------第二种打印输出方法---end----");
		System.out.println();
		System.out.println("-------第三种打印输出方法-转换成数组--start----");
		/**
		 * toArray Object[] toArray() 返回包含此 collection 中所有元素的数组。如果 collection
		 * 对其迭代器返回的元素顺序做出了某些保证,那么此方法必须以相同的顺序返回这些元素。 返回的数组将是“安全的”,因为此 collection
		 * 并不维护对返回数组的任何引用。(换句话说,即使 collection
		 * 受到数组的支持,此方法也必须分配一个新的数组)。因此,调用者可以随意修改返回的数组。
		 * 
		 * 此方法充当了基于数组的 API 与基于 collection 的 API 之间的桥梁。
		 * 
		 * 返回: 包含此 collection 中所有元素的数组
		 */

		Object[] obj = list.toArray();
		for (Object object : obj) {
			News newss = (News) object;
			System.out.println("News [id=" + newss.getId() + "," + " title="
					+ newss.getTitle() + "," + " author=" + newss.getAuthor()
					+ "]");
		}

		System.out.println("-------第三种打印输出方法---end----");
		System.out.println();
		System.out.println("-------第四种打印输出方法-迭代方式--start----");
		/**
		 * iterator Iterator<E> iterator()
		 * 
		 * boolean hasNext() 如果仍有元素可以迭代,则返回 true。
		 * 
		 * E next() 返回迭代的下一个元素。
		 * 
		 * void remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
		 */
		Iterator it = list.iterator();
		while (it.hasNext()) {
			News newss = (News) it.next();
			System.out.println("News [id=" + newss.getId() + "," + " title="
					+ newss.getTitle() + "," + " author=" + newss.getAuthor()
					+ "]");
		}
		System.out.println("-------第四种打印输出方法---end----");
	}
}
5、输出结果:
5
false
-------第一种打印输出方法---start----
[News [id=1, title=张卓1, author=green1]
, News [id=2, title=张卓2, author=green2]
, News [id=3, title=张卓3, author=green3]
, News [id=2, title=张卓2, author=green2]
, News [id=6, title=张卓6, author=green6]
]-------第一种打印输出方法---end----


-------第二种打印输出方法-增强for--start----
News [id=1, title=张卓1, author=green1]
News [id=2, title=张卓2, author=green2]
News [id=3, title=张卓3, author=green3]
News [id=2, title=张卓2, author=green2]
News [id=6, title=张卓6, author=green6]
-------第二种打印输出方法---end----

-------第三种打印输出方法-转换成数组--start----
News [id=1, title=张卓1, author=green1]
News [id=2, title=张卓2, author=green2]
News [id=3, title=张卓3, author=green3]
News [id=2, title=张卓2, author=green2]
News [id=6, title=张卓6, author=green6]
-------第三种打印输出方法---end----

-------第四种打印输出方法-迭代方式--start----
News [id=1, title=张卓1, author=green1]
News [id=2, title=张卓2, author=green2]
News [id=3, title=张卓3, author=green3]
News [id=2, title=张卓2, author=green2]
News [id=6, title=张卓6, author=green6]
-------第四种打印输出方法---end----
6、从上面的打印中可以看出:
  • Set的输出是无序的;
  • Set虽然说具有去重的功能,但是自定义对象增加到Set集合或HashSet集合中,还是有重复的对象,怎么办呢?有什么玄机呢?为什么没有去重呢?我们还是看看java的系统类String,我们在String类中把相同的对象增加进去会去重吗?我们来试试。具体代码如下:
public class HashSetDemo2_String {
	// 需求:
	// 增加新闻元素
	// 获取新闻总数
	// String类,如果在HashSet容器增加元素,如果增加的元素是相同的,就会去重。

	@SuppressWarnings("all")
	// public static void main(String[] args) {
	@Test
	public void testSet() {

		// 创建对象
		// 创建多态的形式,要注意的点:只能调用父类与子类重写的方法,子类特有方法无法调用
		// Set list=new HashSet();//多态的形式。//1.父子关系 2.重写方法 3.父类的引用指向子类对象

		HashSet list = new HashSet();
		String s1 = new String("abc");
		String s2 = new String("abc");
        String s3 = new String("abc");
		// 增加元素
		list.add(s1);
        // 注意:当向set集合中存储相同元素时,add(obj)方法返回的是false.
		list.add(s2);
        list.add(s3);
		// 获取元素总数
		System.out.println(list.size());
		System.out.println();
		//打印输出
		System.out.println(list);
	}
}
7、输出结果:
1

[abc]

8、很显然,java系统类在向Set或HashSet集合里增加元素时,已经完美的去重了。那我们就看看String类里重写了哪些方法,我们来借鉴一下!惊奇的发现了String重写Object超类中的两个方法:一个是equals方法(前面介绍过:Java入门-Java学习路线扩展课程:equals的使用),另一个是hashCode方法。源码如下:
  • 重写equals方法
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
  • 重写hashCode方法

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}
9、原来如此,String类用属性value值作为底层数据来计算hashCode的,即相同的value就一定会有相同的哈希值。如果value值相同,那么调用equals方法比较也是相等的;反过来不一定成立。它不保证相同的哈希值一定就是相同的对象。
10、在Java中,String类有个别对象的属性值不同,但是哈希值相同,比如字符串"gdejicbegh"与字符串"hgebcijedg"具有相同的哈希值-801038016。代码如下:
		HashSet list = new HashSet();
		String s1 = new String("gdejicbegh");
		String s2 = new String("hgebcijedg");
		System.out.println(s1.hashCode()==s2.hashCode());
		System.out.println(s1.hashCode());
		System.out.println(s2.hashCode());
11、输出结果:
true
-801038016
-801038016
12、结论如下:
  • 如果equals比较后相等,则hashCode一定会相等。   更多免费资料请加微信公众号:javaforum
  • 如果hashCode的哈希值相等,equals就不一定相等,注意:它不保证相同的哈希值一定就是相同的对象。
13、小伙伴们是不是有种豁然开朗的感觉?我们来改造一下News.java类,改造代码如下:
package com.javaxyz.equals;

/**
 * @ClassName:News.java
 * @Description:描述信息
 * @Author:DongGaoYun
 * @AuthorEnglishName:Andy
 * @URL:www.javaxyz.com 或 www.gyun.org
 * @Email:DongGaoYun@qq.com
 * @QQ:1050968899
 * @WeiXin:QingYunJiao
 * @WeiXinGongZhongHao: JavaForum
 * @Date:2019-10-22 下午2:23:38
 * @Version:1.0 
 * 完成以下基本代码:  1.属性  2.get和set方法   3.构造方法  4.toString
 * 重写Object的两个方法
 * 1.hashCode方法
 * 2.equals方法
 *  Set集合即可去重。
 * 
 */
public class News {
	// 属性
	private int id;
	private String title;// 标题
	private String author;// 作者

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * @return the title
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * @param title
	 *            the title to set
	 */
	public void setTitle(String title) {
		this.title = title;
	}

	/**
	 * @return the author
	 */
	public String getAuthor() {
		return author;
	}

	/**
	 * @param author
	 *            the author to set
	 */
	public void setAuthor(String author) {
		this.author = author;
	}

	// toString
	@Override
	public String toString() {
		return "News [id=" + id + "," + " title=" + title + "," + " author="
				+ author + "]\n";
	}

	/**
	 * 无参构造方法
	 */
	public News() {
	}

	/**
	 * 有参构造方法
	 * 
	 * @param id
	 * @param title
	 * @param author
	 */
	public News(int id, String title, String author) {
		super();
		this.id = id;
		this.title = title;
		this.author = author;
	}

	/* 
	 * 为什么把prime变量值初始化为31,有以下几个原因:更多免费资料请加微信公众号:javaforum
	 * 1.31这个数字不大也不太小
	 * 2.31是一个奇数,也是一个质数,即只能被1和本身整除的数。
	 * 3.如果选择偶数,乘2相当于移位运算可能导致溢出,数据会丢失
	 * 4.31有个很好的特性,就是用移位和减法来代替乘法,可以得到更好的性能:31*i==(i<<5)-i。现在的JVM可以自动完成这种优化。	 * 
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((author == null) ? 0 : author.hashCode());
		result = prime * result + id;
		result = prime * result + ((title == null) ? 0 : title.hashCode());
		System.out.println("执行的hashCode是:"+result);
		return result;
	}

	/* 
	 * 在我的博文中已经讲过: Java入门-Java学习路线扩展课程:equals的使用 更多免费资料请加微信公众号:javaforum
	 */
	@Override
	public boolean equals(Object obj) {
		//提升效率 判断传入的对象与本对象是否是同一个对象
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())//比较两个对象的字节码文件是否是同一个字节码
			return false;
		News other = (News) obj;//向下转型
		if (author == null) {
			if (other.author != null)
				return false;
		} else if (!author.equals(other.author))
			return false;
		if (id != other.id)
			return false;
		if (title == null) {
			if (other.title != null)
				return false;
		} else if (!title.equals(other.title))
			return false;
		return true;
	}
}
14、测试代码:
package com.javaxyz.test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.junit.Test;

import com.javaxyz.equals.News;

/**
 * @ClassName:HashSetDemo.java
 * @Description:Set的运用 
 * @Author:DongGaoYun
 * @AuthorEnglishName:Andy
 * @URL:www.javaxyz.com 或 www.gyun.org
 * @Email:DongGaoYun@qq.com
 * @QQ:1050968899
 * @WeiXin:QingYunJiao
 * @WeiXinGongZhongHao: JavaForum
 * @Date:2019-10-25 
 * @Version:1.0 HashSet 优势: 去重 特有功能:
 * 
 */
public class HashSetDemo1 {
	// 需求:
	// 增加新闻元素
	// 获取新闻总数
	// 操作HashSet容器,移除元素
	// 判断是否包含此元素
	// 打印输出四种方式
	// String类,如果在HashSet容器增加元素,如果增加的元素是相同的,就会去重。

	@SuppressWarnings("all")
	// public static void main(String[] args) {
	@Test
	public void testSet() {

		// 创建对象
		// 创建多态的形式,要注意的点:只能调用父类与子类重写的方法,子类特有方法无法调用
		Set list = new HashSet();// 多态的形式。//1.父子关系 2.重写方法 3.父类的引用指向子类对象
		String s1 = new String("gdejicbegh");
		String s2 = new String("hgebcijedg");
		System.out.println(s1.hashCode()==s2.hashCode());
		System.out.println(s1.hashCode());
		System.out.println(s2.hashCode());
		// list.add(s1);
		// list.add(s2);
		//System.out.println(list.size());
		
		
		
		
		News news1 = new News(1, "张卓1", "green1");
		News news2 = new News(2, "张卓2", "green2");
		News news11 = new News(2, "张卓2", "green2");
		News news3 = new News(3, "张卓3", "green3");
		News news4 = new News(4, "张卓4", "green4");
		News news5 = new News(5, "张卓5", "green5");
		News news6 = new News(6, "张卓6", "green6");
		News news7 = new News(7, "张卓7", "green7");
		News news8 = new News(8, "张卓8", "green8");
		// 插入数据
		list.add(news1);
		list.add(news2);
		list.add(news3);
		// 注意set是无序的,没有索引,所以报错             更多免费资料请加微信公众号:javaforum
		// list.add(1,news4);
		// 插入数据
		list.add(news6);
		//注意:自定义对象重写equals和hashCode方法后,如果是重复元素,这时就会返回false
		System.out.println(list.add(news11));
		// 总条数
		System.out.println(list.size());

		// 操作HashSet容器,移除元素
		/*
		 * list.remove(0); list.remove(news1);
		 */
		// 判断是否包含此元素
		System.out.println(list.contains(news7));
		// list
		System.out.println("-------第一种打印输出方法---start----");
		System.out.print(list);
		System.out.println("-------第一种打印输出方法---end----");
		System.out.println();
		//System.out.println("-------第二种打印输出方法-普通for--start----");
		// 普通for不能用

		/*
		 * for (int i = 0; i < list.size(); i++) { News newss = (News)
		 * list.get(i); System.out.println("News [id=" + newss.getId() + "," +
		 * " title=" + newss.getTitle() + "," + " author=" + newss.getAuthor() +
		 * "]"); }
		 */

		//System.out.println("-------第二种打印输出方法---end----");
		System.out.println();
		System.out.println("-------第二种打印输出方法-增强for--start----");
		for (Object object : list) {
			News newss = (News) object;
			System.out.println("News [id=" + newss.getId() + "," + " title="
					+ newss.getTitle() + "," + " author=" + newss.getAuthor()
					+ "]");
		}
		System.out.println("-------第二种打印输出方法---end----");
		System.out.println();
		System.out.println("-------第三种打印输出方法-转换成数组--start----");
		/**
		 * toArray Object[] toArray() 返回包含此 collection 中所有元素的数组。如果 collection
		 * 对其迭代器返回的元素顺序做出了某些保证,那么此方法必须以相同的顺序返回这些元素。 返回的数组将是“安全的”,因为此 collection
		 * 并不维护对返回数组的任何引用。(换句话说,即使 collection
		 * 受到数组的支持,此方法也必须分配一个新的数组)。因此,调用者可以随意修改返回的数组。
		 * 
		 * 此方法充当了基于数组的 API 与基于 collection 的 API 之间的桥梁。
		 * 
		 * 返回: 包含此 collection 中所有元素的数组                                  更多免费资料请加微信公众号:javaforum
		 */

		Object[] obj = list.toArray();
		for (Object object : obj) {
			News newss = (News) object;
			System.out.println("News [id=" + newss.getId() + "," + " title="
					+ newss.getTitle() + "," + " author=" + newss.getAuthor()
					+ "]");
		}

		System.out.println("-------第三种打印输出方法---end----");
		System.out.println();
		System.out.println("-------第四种打印输出方法-迭代方式--start----");
		/**
		 * iterator Iterator<E> iterator()
		 * 
		 * boolean hasNext() 如果仍有元素可以迭代,则返回 true。
		 * 
		 * E next() 返回迭代的下一个元素。                          更多免费资料请加微信公众号:javaforum
		 * 
		 * void remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
		 */
		Iterator it = list.iterator();
		while (it.hasNext()) {
			News newss = (News) it.next();
			System.out.println("News [id=" + newss.getId() + "," + " title="
					+ newss.getTitle() + "," + " author=" + newss.getAuthor()
					+ "]");
		}
		System.out.println("-------第四种打印输出方法---end----");
	}
}
15、输出结果:
true
-801038016
-801038016
false
4
false
-------第一种打印输出方法---start----
[News [id=1, title=张卓1, author=green1]
, News [id=2, title=张卓2, author=green2]
, News [id=6, title=张卓6, author=green6]
, News [id=3, title=张卓3, author=green3]
]-------第一种打印输出方法---end----


-------第二种打印输出方法-增强for--start----
News [id=1, title=张卓1, author=green1]
News [id=2, title=张卓2, author=green2]
News [id=6, title=张卓6, author=green6]
News [id=3, title=张卓3, author=green3]
-------第二种打印输出方法---end----

-------第三种打印输出方法-转换成数组--start----
News [id=1, title=张卓1, author=green1]
News [id=2, title=张卓2, author=green2]
News [id=6, title=张卓6, author=green6]
News [id=3, title=张卓3, author=green3]
-------第三种打印输出方法---end----

-------第四种打印输出方法-迭代方式--start----
News [id=1, title=张卓1, author=green1]
News [id=2, title=张卓2, author=green2]
News [id=6, title=张卓6, author=green6]
News [id=3, title=张卓3, author=green3]
-------第四种打印输出方法---end----

16、由此可见,要想将自定义类的对象存入HashSet集合里去重,需要注意以下三点:

  • 自定义类中必须同时重写equals()和hashCode()方法
  • hashCode(): 属性值相同的对象返回值必须相同, 属性值不同的返回值尽量不同(提高效率)
  • equals(): 属性值相同返回true, 属性值不同返回false,返回false的时候存储
17、HashSet去重原理:
17.1、使用HashSet集合调用add()方法存储对象之前,应该注意尽量使重写的hashCode()方法返回的值不同,减少调用equals方法,提升性能;在调用add方法时,系统会先调用对象的hashCode()方法得到一个哈希值, 然后在HashSet集合中比较是否有哈希值相同的对象
  • 如果没有哈希值相同的对象就会直接存入HashSet集合
  • 如果有哈希值相同的对象, 就和哈希值相同的对象逐个调用equals()方法进行比较,结果为false就直接存入, 为true则不存

       小伙伴们,本章已经结束,你们都懂了吗?我花了四个小时的时间编写,记得关注、点赞、分享和关注微信公众号(javaforum)噢!有疑问或好的建议请与我联系噢!持续更新!敬请关注!


———— 精 选 文 章 ————
  1. Java入门-Java学习路线课程第一课:初识JAVA
  2. Java入门-Java学习路线课程第二课:变量与数据类型
  3. Java入门-Java学习路线课程第三课:选择结构
  4. Java入门-Java学习路线课程第四课:循环结构
  5. Java入门-Java学习路线课程第五课:一维数组
  6. Java入门-Java学习路线课程第六课:二维数组
  7. Java入门-Java学习路线课程第七课:类和对象
  8. Java入门-Java学习路线课程第八课:方法和方法重载
  9. Java入门-Java学习路线扩展课程:equals的使用
  10. Java入门-Java学习路线课程面试篇:取商 / 和取余(模) % 符号的使用
  11. Java进阶-Java学习路线课程第一课:Java集合框架-ArrayList和LinkedList的使用
  12. Spring框架-Java学习路线课程第一课:Spring核心
  13. Spring框架-Java学习路线课程:Spring的扩展配置
  14. Springboot框架-Java学习路线课程:Springboot框架的搭建之maven的配置
  15. java学习:在给学生演示用Myeclipse10.7.1工具生成War时,意外报错:SECURITY: INTEGRITY CHECK ERROR
  16. 使用jquery发送Ajax请求的几种异步刷新方式
  17. idea Springboot启动时内嵌tomcat报错- An incompatible version [1.1.33] of the APR based Apache Tomcat Native
  18. 一个简单的SSM框架Demo(登录(包含拦截器)和注销

更多免费资源请关注微信公众号:

©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页