黑马程序员——集合类(2)

------<ahref="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

Map集合:

该集合存储键值对,一对一对往里存,而且要保证键的唯一性(值可以重复)。和Collection集合的一个主要区别就是:当判断新添的元素和原有元素一致时,Collection会保留原有元素,而Map会用新添元素替换原有元素。

1.       添加

put (K key, V value)

putAll(Map<? extends K,? extends V> m)

2.       删除

clear()

remove(Object key)

3.       判断

containsValue(Object value)

containsKey(Object key)

isEmpty()

4.       获取

get(Object key)

size()

values()

entrySet()         (需要重点掌握)

keySet()             (需要重点掌握)

Map集合的三个重要子类

Hashtable:底层是哈希表数据结构,用作键的对象必须实现 hashCode 方法和 equals 方法。不可以存入null键null值。该集合是线程同步的。来自JDK1.0效率低。

HashMap:底层是哈希表数据结构,用作键的对象必须实现 hashCode 方法和 equals 方法。允许使用null键null值。该集合是线程不同步的。JDK1.2效率高。(实际开发中主要用HashMap,它是Hashtable的升级版)

TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

 

其实Set集合在底层使用的就是Map集合,Map集合里面有两个元素:键和值,Set去掉一个元素即可。

 

可以通过get方法的返回值是否为null来判断一个键是否存在。(但是HashMap允许使用空键空值,所以最好还是用containsKey等常规方法来判断)

 

如果用values()方法(得到按照Map中键的升序排列的值的Collection集合)获取Map的返回值的话会发现结果是无序的,因为HashMap是哈希结构的。

【注意】Collection集合的add方法返回的是布尔型,比如说当HashSet存了两个相同元素会返回假,于是添加失败。但是Map集合的put方法返回的是那个键对应的原来的那个Value值,而put相同的键时会覆盖,新值覆盖替换掉原有的值。

Map集合的取出原理:将Map集合转成Set集合。再通过迭代器取出。

Map集合的两种取出方式:

1.       Set<K> keySet:将map中所有的键存入到Set集合,因为Set具备迭代器,而Map不具备。因此可以用迭代方式取出每一个键,再根据Map的get方法,获取每一个键对应的值。

2.       Set<Map.Entry<K,V>> entrySet:将Map集合中的映射关系存入到了Set集合中去,而这个关系的数据类型就是Map.Entry。那么关系的对象Map.Entry获取到后,就可以通过Map.Entry中getKey和getValue方法获取关系中的键和值。

用上述两种方法获取Map集合中值的小例子,代码如下:

import java.util.*;
class MapDemo 
{
	public static void main(String[] args) 
	{
		Map<String, String> m = new HashMap<String, String>();
		m.put("01","张三1");
		m.put("02","张三2");
		m.put("03","张三3");
		m.put("04","张三4");

		Set<String> keySet= m.keySet();
		for (Iterator<String> it = keySet.iterator(); it.hasNext(); )
		{
			String key = it.next();
			String value = m.get(key);
			sop("key:"+key+", value:"+value);
		}

		sop("----------------------华丽丽的分割线----------------------");

		Set<Map.Entry<String, String>> entrySet = m.entrySet();
		for (Iterator<Map.Entry<String, String>> it = entrySet.iterator(); it.hasNext(); )
		{
			Map.Entry<String, String> me = it.next();
			sop("key:"+me.getKey()+", value:"+me.getValue());
		}
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

【注意】Map集合的所有子类,不管是TreeMap还是HashMap用entrySet()方法返回的都是Set集合而不是TreeSet或者HashSet集合!

其实Map.Entry也是一个接口,它是Map接口中的一个内部接口。内部接口必须被公有和静态修饰符修饰,因为它的父类接口无法创建对象这样就无法调用到子接口了,Map.Entry这个内部接口的大概定义方法如下:


与内部类一样,只有内部接口在成员位置上才能加静态修饰符,二者互为充要条件,因为如果内部接口不是静态的,我们必须要创建父接口的对象才能调用内部接口,而接口没办法创建对象,所以内部接口必须静态。

至于public修饰符,设置的目的是为了确保能被外部的类复写。

为什么Entry要充当Map接口的内部接口,为什么不定义在外面?

因为Entry代表着映射关系,而我们先有Map集合才有映射关系,所以这个关系是Map集合中的内部事务。而且这个关系在直接访问Map集合中的元素,所以我们把Entry定义成Map的内部规则。

 

         上面的概念比较抽象可能不太好理解,接下来我们跟着这个例子来深入体会。

练习1

每个学生都有对应的归属地。学生Studen类,地址String类。

学生具有属性:姓名,年龄。

注意:姓名年龄相同的视为同一个学生。

代码详见:

import java.util.*;
class MapTest 
{
	public static void main(String[] args) 
	{
		Student s1 = new Student();
		Student s2 = new Student();
		Student s3 = new Student();
		Student s4 = new Student();
		s1.setName("张三1");
		s1.setAge(39);
		s2.setName("张三2");
		s2.setAge(22);
		s3.setName("张三3");
		s3.setAge(29);
		s4.setName("张三4");
		s4.setAge(34);

		HashMap<Student, String> hm = new HashMap<Student, String>();//按照哈希表顺序排
		hm.put(s1,"平谷");
		hm.put(s2,"大同");
		hm.put(s3,"张家口");
		hm.put(s4,"博卡拉");
		hm.put(s4,"博卡拉1");//如果判断键相同,会用新的值替代旧的

		Set<Student> keySet = hm.keySet();//第一种取出方式keySet
		for (Iterator<Student> it = keySet.iterator(); it.hasNext(); )
		{
			Student s = it.next();
			String address = hm.get(s);
			sop(s+"-----"+address);
		}

		sop("----------------------华丽丽的分割线----------------------");

		TreeMap<Student, String> tm = new TreeMap<Student, String>();//使用的是Student里面定义的排序方式,按照compareTo定义的顺序排(姓名>年龄)
		tm.put(s1,"平谷");
		tm.put(s2,"大同");
		tm.put(s3,"张家口");
		tm.put(s4,"博卡拉");
		tm.put(s4,"博卡拉1");//如果判断键相同,会用新的值替代旧的

		for (Iterator<Map.Entry<Student,String>> it = tm.entrySet().iterator(); it.hasNext(); )//第二种取出方式entrySet,这里和迭代器结合成了一条语句
		{
			Map.Entry<Student,String> me = it.next();
			Student s = me.getKey();
			String address = me.getValue();
			sop("姓名:"+s.getName()+";年龄:"+s.getAge()+";来自:"+address);
		}

		
		sop("----------------------华丽丽的分割线----------------------");

		TreeMap<Student, String> tm2 = new TreeMap<Student, String>(new AgeComparator());//使用的是比较器comparator里面定义的排序方式覆盖Student类里面的排序方式(年龄>姓名)
		tm2.put(s1,"平谷");
		tm2.put(s2,"大同");
		tm2.put(s3,"张家口");
		tm2.put(s4,"博卡拉");
		tm2.put(s4,"博卡拉1");//如果判断键相同,会用新的值替代旧的

		for (Iterator<Map.Entry<Student,String>> it = tm2.entrySet().iterator(); it.hasNext(); )//第二种取出方式entrySet,这里和迭代器结合成了一条语句
		{
			Map.Entry<Student,String> me = it.next();
			Student s = me.getKey();
			String address = me.getValue();
			sop("姓名:"+s.getName()+";年龄:"+s.getAge()+";来自:"+address);
		}


	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

class Student implements Comparable<Student>
{
	private String name;
	private int age;
	public void setName(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
	public void setAge(int age)
	{
		this.age = age;
	}
	public int getAge()
	{
		return age;
	}
	public int hashCode()
	{
		return name.hashCode()+age*34;
	}
	public boolean equals(Object obj)//equals方法没有泛型,如果我们这里不输入Object类的话无法覆盖父类同名方法,最多相当于重载。
	{
		if (!(obj instanceof Student))
			throw new ClassCastException("类型不匹配");//输出异常,该异常是RuntimeException的子类,会让程序停止。
		Student s = (Student)obj;
		return this.name.equals(s.name) && this.age==(s.age);
	}
	public int compareTo(Student s)
	{
		int x = this.name.compareTo(s.name);
		if (x == 0)
			return new Integer(this.age).compareTo(new Integer(s.age));//这里int类型的值是变量无法调用方法,必须转为Integer类型才能使用compareTo方法
		return x;
	}
	public String toString()//覆盖Object类中的toString,建立学生对象自定义的字符串表现形式,这样再打印学生对象时,显示的就是我们自定义的格式了。
	{
		return "To String: "+name+", "+age;
	}
}
class AgeComparator implements Comparator<Student>
{
	public int compare(Student s1, Student s2)
	{
		int x = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		if (x == 0)
			return s1.getName().compareTo(s2.getName());//这里int类型的值是变量无法调用方法,必须转为Integer类型才能使用compareTo方法
		return x;
	}
}

练习心得:

如果一个类能产生很多对象,应用很广的话,它的对象以后可能会被存到各种常用容器里,如HashMap,TreeMap等,因此为了做好准备,我们在定义的时候最好让它具备一个自然顺序(实现Comparable),并有我们定义的hashCode和equals以及compareTo方法。

ClassCastException是RuntimeException的子类,会让程序停止。

覆盖Object类中的toString,建立学生对象自定义的字符串表现形式,这样再打印学生对象时,显示的就是我们自定义的格式了。


练习2:

输入一个字符串,显示出字符串中每个字符的个数

格式:

字符(个数) 字符(个数) 字符(个数)…

代码示例:

import java.util.*;
class MapTest2 
{
	public static void main(String[] args) 
	{
		sop(countChar("boundage & submission; Madison Ivy"));
	}
	public static String countChar(String str)
	{
		char[] chs = str.toCharArray();
		TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();//键是Character类型的,它里面已经实现了Comparable所以会自动排序,不用我们定义

		//我们肯定拿字母作为键,次数是值。但是不能把char和int作为Map的存储对象,因为泛型里面接收的都是引用数据类型,所以必须找到char和int对应的基本数据类型包装类Character和Integer

		/*我的学习里第一种判断的写法
		Integer value;
		for (int x = 0; x<chs.length; x++)
		{
			if (!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))
				continue;

			value = tm.get(chs[x]);
			if (value==null)
				value=1;
			value++;
			tm.put(chs[x],value);
		}
		*/
		/*我的学习视频里第二种写法
		int count = 0;
		for (inx x=0; x<chs.length; x++)
		{
			if (!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))
				continue;

			Integer value = tm.get(chs[x]);

			if (value!=null)
				count = value;//Integer类型的值可以赋给int
			count++;
			tm.put(chs[x],count);
			//第一次用a字母作为键去找集合。那么集合没有a这个键,所以也没有对应的次数。返回null。因此我们应该判断如果返回值为null,就将a字母和1(初始化的0+1)存入集合。		如果指定键已存在,说明有对应的键值对。就将对应的次数取出,并自增后再重新存入集合。

			count = 0;
			//指定计数器value在被用完后要清零,而如果把int count = 0放在循环内部也可以起到相通的作用,但是每次循环读到int count = 0;都要在内存里开辟-释放空间,不优化。因此初始化定义不要在循环里面而要在外面。
		}*/
		/*//我的改良版(亲测有效),少了个变量int count但是内存中可能需要多执行几次tm集合的get方法
		Integer value = 0;
		for (int x = 0; x<chs.length; x++)
		{
			if (!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))
				continue;

			if (tm.get(chs[x])!=null)
				value = tm.get(chs[x]);
			tm.put(chs[x],++value);
			value=0;
		}*/

		//我的改良版升级版(亲测有效),虽然语句比改良版多了1行,但不用定义变量int count也不用多执行tm的get方法
		Integer value;
		for (int x = 0; x<chs.length; x++)
		{
			if (!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))
				continue;
			//要进行一个判断,如果值是非字母的符号的处理方案,不是的话continue继续循环。

			value = tm.get(chs[x]);

			if (value==null)
				value = 0;
			value++;
			tm.put(chs[x],value);
		}
		StringBuilder sb = new StringBuilder();
		for (Iterator<Map.Entry<Character,Integer>> it = tm.entrySet().iterator(); it.hasNext(); )
		{
			Map.Entry<Character, Integer> me = it.next();
			sb.append(me.getKey()+"("+me.getValue()+")");
		}
		return sb.toString();//StringBuilder的toString一定要写,因为接受的返回类型是String而sb是StringBuilder字符缓冲区
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

练习3:一对多的映射

一个学校有多个教室,每个教室有多个学生,学生的姓名和学号有映射关系 如:

“就业” “01” “张三”

第一种方法:建立嵌套的映射方法:学号映射姓名,教室映射<学号与姓名的映射>

代码示例:

import java.util.*;
class MapTest3 //第一种方法:建立嵌套的映射方法:学号映射姓名,教室映射<学号与姓名的映射>  第二种方法见 MapTest4.java
{
	public static void main(String[] args) 
	{
		sop("第一种方法");
		HashMap<String,HashMap<Integer, String>> czbk = new HashMap<String,HashMap<Integer, String>>();//创建学校传智播客
		HashMap<Integer, String> yure = new HashMap<Integer, String>();
		HashMap<Integer, String> jiuye = new HashMap<Integer, String>();//创建两个班级
		czbk.put("预热",yure);
		czbk.put("就业",jiuye);//把两个班级放到传智播客旗下
		yure.put(01, "张三");
		yure.put(02, "李四");
		yure.put(03, "王二麻子");
		jiuye.put(01,"jack");
		jiuye.put(02,"rose");
		jiuye.put(03,"sam");//班级里面放的是一个个学号与姓名的映射

		getClassInfo(czbk);
	}
	public static void getClassInfo(HashMap<String,HashMap<Integer, String>> schoolName)
	{
		for (Iterator<Map.Entry<String,HashMap<Integer, String>>> it = schoolName.entrySet().iterator();it.hasNext(); )
		{
			Map.Entry<String,HashMap<Integer, String>> classes = it.next();
//			String className = classes.getKey();//得到班级名称,没用
			sop(classes.getKey());
			getStudentInfo(classes.getValue());//得到班级实体
		}
		
	}
	public static void getStudentInfo(HashMap<Integer,String> className)
	{
		for (Iterator<Map.Entry<Integer,String>> it = className.entrySet().iterator();it.hasNext(); )
		{
			Map.Entry<Integer,String> me = it.next();
			sop(me.getKey()+"::"+me.getValue());
		}
		
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

第二种方法:建立嵌套的映射方法:学生对象里面有学号和姓名,教室映射<学生对象> 

代码示例:

import java.util.*;
class MapTest4 //第二种方法:建立嵌套的映射方法:学生对象里面有学号和姓名,教室映射<学生对象>  第一种方法见 MapTest3.java
{
	public static void main(String[] args) 
	{
		sop("第二种方法");
		HashMap<String,List<Student>> czbk = new HashMap<String,List<Student>>();//创建学校传智播客
		List<Student> yure = new ArrayList<Student>();
		List<Student> jiuye = new ArrayList<Student>();//创建两个班级
		czbk.put("预热",yure);
		czbk.put("就业",jiuye);//把两个班级放到传智播客旗下
		yure.add(new Student(01, "张三"));
		yure.add(new Student(02, "李四"));
		yure.add(new Student(03, "王二麻子"));
		jiuye.add(new Student(01,"jack"));
		jiuye.add(new Student(02,"rose"));
		jiuye.add(new Student(03,"sam"));//班级的集合里面放的是一个个学生对象

		getClassInfo(czbk);
	}
	public static void getClassInfo(HashMap<String,List<Student>> schoolName)
	{
		for (Iterator<Map.Entry<String,List<Student>>> it = schoolName.entrySet().iterator();it.hasNext(); )
		{
			Map.Entry<String,List<Student>> classes = it.next();
//			String className = classes.getKey();//得到班级名称,没用
			sop(classes.getKey());
			getStudentInfo(classes.getValue());//得到班级实体
		}
		
	}
	public static void getStudentInfo(List<Student> className)
	{
		for (Iterator<Student> it = className.iterator();it.hasNext(); )
		{
			Student s = it.next();
			sop(s);
		}
		
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

class Student
{
	private String name;
	private int id;
	Student(int id, String name)
	{
		this.name = name;
		this.id = id;
	}
	public String toString()//覆盖Object类中的toString,建立学生对象自定义的字符串表现形式,这样再打印学生对象时,显示的就是我们自定义的格式了。
	{
		return "To String: "+name+", "+id;
	}
}

集合框架工具类

这是专门用于对集合进行操作的工具类:Collections。

工具类

这个类存在的目的仅仅是对外提供方法,而静态方法用的最简单,因此工具类里面方法都是静态的。没有对外提供构造函数,不需要创建对象。没有封装特有数据。

例如sort方法可以对List集合进行排序。

public static<T extends Comparable<? super T>> void sort(List<T> list)

所操作的对象List的泛型元素T必须是Comparable的子类才可以否则无法比,并且他们的比较器的泛型可以是T以及T的父类,用父类方法也可以比。我们之前已经说过Comparable和Comparator一般后面跟的都是<?super T>。

 

如果不愿意用T对象原有自带的比较器,我们可以自定义一个比较器。

public static <T> voidsort(List<T> list, Comparator<? super T> c)

 

另外取最大值最小值的maxmin方法必然也要比较,与上面类似,只是对T的限定稍有不同。

static <T extends Object &Comparable<? super T>> T max(Collection<? extends T> coll) 

static <T> T  max(Collection<? extends T> coll,Comparator<? super T> comp) 

 

另外还有用二分法查找的函数也需要用到比较功能,并且只能是List集合,因为二分法查找涉及到角标,返回的是元素的角标。

static <T> int  binarySearch(List<? extendsComparable<? super T>> list, T key)

static <T> int  binarySearch(List<? extends T> list, Tkey, Comparator<? super T> c)

这里面如果输入的key不存在,返回(它应该插入位置+1)的负数,如应该在2,返回-3

 

其他常用方法:

         使用指定元素替换指定列表中的所有元素。

static <T> voidfill(List<? super T> list, T obj);

 

使用另一个值替换列表中出现的所有某一指定值。

static <T>boolean replaceAll(List<T> list, T oldVal, T newVal);

反转指定列表中元素的顺序。

static voidreverse(List<?> list);

在指定列表的指定位置处交换元素。(reverse方法内部调用swap方法)

static voidswap(List<?> list, int i, int j);

 

返回的都是一个比较器,该比较器强行逆转原有比较器,前者逆转T实现的Comparable的比较方法,后者直接逆转传入的比较器。

reverseOrder()与reverseOrder(Comparator<T> comp);

如:TreeSet<String> ts = newTreeSet<String>(Collections.reverseOrder());逆转的是String自带的比较方式产生一个比较器,并把比较器传入TreeSet当中。

 

此外还有:

static <T>List<T> synchronizedList(List<T> list) 

static <T>Set<T> synchronizedSet(Set<T> s)

等方法,这些方法将非同步集合转化成同步的集合,线程安全。

 

洗牌,很简单。将list集合中的元素打乱顺序随机排放。

static voidshuffle(List<?> list);

 

Arrays:用于操作数组的工具类。里面都是静态方法。

与Collections相对应的工具类,里面的方法都是用于操作数组的。

值得庆贺的是,该类复写的toString方法能将数组转换成字符串形式,便于打印。我们以前的做法是写个循环遍历每个数组元素,并用StringBuilder存储。现在我们直接调用就可以了。

还有一种能将数组转换成字符串形式,那就是String类的构造函数。

构造函数:     String(byte[]):

String(byte[],offset, count):将字节数组中的一部分转成字符串。

但是二者有区别。

前者将数组里面存的元素提取出来,不论元素是什么类型的,都转成String类型。(类似于System.out.print()方法)

而后者将byte里面存的数字进行查表,并把对应的字母转成String类型。

 

将数组变成list集合。

asList();

static <T> List<T> asList(T... a)       T…表示的是可变参数,下文会详细介绍。

把数组变成集合的好处在于:可以使用集合的思想和方法来操作数组中的元素。因为虽然数组是一个对象,但是它的功能比较少。比如说想要查找数组中是否有某个元素需要遍历判断,而转化成集合后,只需一个集合自带的contains方法就解决了。

【注意】将数组变成集合,不可以使用集合的增删方法,因为数组的长度是固定的。否则会发生UnsupportedOperationException(不支持操作异常)

【另外注意】如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。

如果数组中的元素都是基本数据类型,那么会将该数组这个整体作为集合中的元素存在,因为集合中只能存储对象,不能存储基本数据类型,而数组转list集合又不支持自动装箱(不能把数组中的int类型转化为Integer对象)。数组里面的元素定义成什么类型,集合就用什么类型的容器接收。

 

集合的toArray方法可以把集合转化成数组。

<T> T[] toArray(T[]a)

【但是注意】这里面的传入参数,指定类型的数组T[] a长度定义为多少呢?

当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组,长度为集合的size。

当指定类型的数组长度大于了集合的size,那么不会创建新数组,而是使用传递进来的数组,多出来的空位都是null。所以创建一个刚刚好的数组最优,因为null浪费空间,而第一种情况创建新数组也要开辟新空间。

将集合变数组的意义:

为了限定对元素的操作,不需要进行增删操作了。

 

高级for循环:(1.5版本出现的新特性)

是为了对繁琐的迭代器简化而进行的升级,便于取出集合中的元素。

局限性:只能对集合中的元素取出,而不能做修改等操作。

格式:

for(数据类型 变量名 : 被遍历的集合(只有collection没有map因为它不支持迭代)或者数组)

{

}

而Iterator可以remove,而listiterator增删改查都可以。

原因:for循环里面定义的那个变量指向集合中的元素,对它进行操作只是修改了指向,而具体的对象没有变化。

另外高级for循环也可以遍历数组。写法与针对集合一样。

传统for循环和高级for循环的区别:

高级for有一个局限性,必须有被遍历的目标。因此建议在遍历数组的时候,还是希望使用传统for,因为传统for可以定义角标。

凡是支持迭代器的集合都支持高级for,因为高级for就是迭代器的简写形式。

 

可变参数(JDK1.5)

有的时候我们会碰到这样一种情况:某个函数需要我们传递参数,传递哪种类型的参数可以确定,但是无法确定这种参数的个数,比如上面那个数组转集合的方法,比如说我们知道要传String类型的参数,但是传2个也可以,3个也可以,最后反正都会放到集合里面。而这时如果我们用传统的重载方法,这不现实,因为需要复写无数次,扩展性相当差。而我们也可以建立一个数组,把需要传递进去的同类型参数放到这个数组里,把数组这个对象作为参数传递给目标函数,可是这么做也稍微有些麻烦,存在数组这个中间环节。于是JDK1.5之后就产生了可变参数,它其实就是数组参数的简写形式。

好处:不用每一次都手动地建立数组对象。(虚拟机每次代替我们new数组)

只要将要操作的元素作为参数传递即可。虚拟机隐式地将这些参数封装成了数组。(与高级for循环一样,底层调用的还是迭代器),而直接往这个函数里面传入这种元素所组成的数组也是可以的,相当于完成了本来由虚拟机代劳的部分。上面提到的static <T> List<T> asList(T... a) 方法接收一组T类型的参数,也接受一个T类型所组成的数组。能且只能接受一个数组。这样才有了我们这个数组转集合的方法。

 

格式:参数类型后面三个点,如:int … a,可以传任意个数的int类型的参数,不传任何参数也行,此时数组长度为0。

数组里面存任意类型的参数都可以。

可变参数的唯一一条注意事项:可变参数一定要定义在参数列表的最后面。如果可变参数后面还有定义好的传统参数,如:float f, int… arr, String str那么虚拟机分不清界限在哪,它会把从第二个参数开始一直到最后的所有元素都封装成一个int[] arr类型的数组,而我们最后传入的要是String类型的显然会报错,编译不能通过。

静态导入

如果重复调用一个包里面的类,或者一个类里面的成员时,可以统一导入,编程的时候就不用写包名或者类名了。

当类名重名时,需要指定具体的包名。

当方法重名时,指定具备所属的对象或者类(当方法是静态的时)。

如图,当AB两个包都有Demo类时,想要调用必须指定具体包名。(当出现Arrays的同名方法时,单单导入Arrays包还不够,在重名方法前还是要加上Arrays.)

import java.util.*;                                    导入java.util包中所有类和接口。

import static java.lang.System.*;        导入System类中所有静态成员。

import static java.util.Arrays.*;  导入Arrays类中所有的静态成员。

凡是加静态的都是某个类中所有的静态成员,凡是不加静态导入的都是某个包中所有的类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值