接口与抽象类的相同点:
接口与抽象类的不同点:
当类实现接口的时候,类要实现接口中所有的方法,否则类必须声明为抽象的类。类使用implements关键字实现接口。
接口使用关键字interface来声明。
接口中的抽象方法具有public 和abstract 修饰符,也只能是这两个修饰符。
//每个类均为单独文件
public interface Shape {
public double area(); // 计算面积
public double perimeter(); // 计算周长
}
public class Circle implements Shape { // Circle 类实现Shape 接口
double radius; // 半径
public Circle(double radius) { // 定义Circle 类的构造方法
this.radius = radius;
}
public double area() { // 重写实现接口定义的抽象方法
return Math.PI * radius * radius;
}
public double perimeter() {
return 2 * Math.PI * radius;
}
}
public class Rectangle implements Shape { // Rectangle 类实现Shape 接口
double a; // 长或宽
double b; // 长或宽
public Rectangle(double a, double b) { // 定义Circle 类的构造方法
this.a = a;
this.b = b;
}
public double area() { // 重写实现接口定义的抽象方法
return a * b;
}
public double perimeter() {
return 2 * (a + b);
}
}
使用default 关键字在接口修饰一个非抽象的方法,这个特征又叫扩展方法。
public interface InterfaceNew {
public double method(int a);
public default void test() {
System.out.println("Java 8 接口新特性");
}
}
实现了InterfaceNew 接口的子类只需实现一个calculate()方法即可,test()方法在子类中可以直接使用。
用父类的变量去引用不同的子类,在调用这个相同的方法的时候得到的结果和表现形式就不一样了,这就是多态,调用相同的方法会有不同的结果。
public class ShapeTest {
public static void main(String[] args) {
Shape s1 = new Circle(10.0); // 体现多态的地方
System.out.println("圆形的面积是:" + s1.area());
System.out.println("圆形的周长是:" + s1.perimeter());
Shape s2 = new Rectangle(5.0, 10.0); // 体现多态的地方
System.out.println("矩形的面积是:" + s2.area());
System.out.println("矩形的周长是:" + s2.perimeter());
}
}
Shape 是一个接口,没有办法实例化对象,但可以用Circle 类和Rectangle 类来实例化对象,也就实现了接口的多态。实例化产生的对象s1 和s2 拥有同名的方法,但各自实现的功能却不一样。
实现一个接口时,必须实现所有的方法,又是只需要其中的一些方法,这里就要用到适配接口。
public interface InterfaceAdapter { // 定义接口
public void email();
public void sms();
}
public abstract class Wrapper implements InterfaceAdapter {
// 写一个抽象类管理接口
public void email() {
}
public void sms() {
}
// 方法体不需要具体实现,可以为空,具体类在需要时可以重写该方法
}
public class S1 extends Wrapper {
// 继承抽象类,重写所需的方法,这里重写了email()方法,没有重写sms()方法
public void email() {
System.out.println("发电子邮件");
}
}
public class Test {
public static void main(String[] args) {
S1 ss = new S1();
ss.email();
}
}
class 内嵌套interface:
这时接口可以是public、private 和package。重点在private 上,被定义为私有的接口只能在接口所在的类中实现。
由于接口的元素必须是public 的,所以被嵌套的接口自动就是public 的,而不能定义成private 的。
接口回调是指可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。
public interface Shape {
public double area(); // 计算面积
public double perimeter(); // 计算周长
}
public class Circle implements Shape { // Circle 类实现Shape 接口
double radius; // 半径
public Circle(double radius) { // 定义Circle 类的构造方法
this.radius = radius;
}
public double area() { // 重写实现接口定义的抽象方法
return Math.PI * radius * radius;
}
public double perimeter() {
return 2 * Math.PI * radius;
}
}
public class Rectangle implements Shape { // Rectangle 类实现Shape 接口
double a; // 长或宽
double b; // 长或宽
public Rectangle(double a, double b) { // 定义Circle 类的构造方法
this.a = a;
this.b = b;
}
public double area() { // 重写实现接口定义的抽象方法
return a * b;
}
public double perimeter() {
return 2 * (a + b);
}
}
public class Show { // 定义一个类用于实现显示功能
public void print(Shape s) // 定义一个方法,参数为接口类型
{
System.out.println("面积:" + s.area());
System.out.println("周长:" + s.perimeter());
}
}
public class Test { // 测试类
public static void main(String[] args) {
Show s1 = new Show();
s1.print(new Circle(10.0));
// 接口回调,将Shape e 替换成 new Circle(10.0)
s1.print(new Rectangle(5.0, 10.0));
// 接口回调,将Shape e 替换成 new Rechtangle(5.0,10.0)
// 使用接口回调的最大好处是可以灵活地将接口类型参数替换为需要的具体类
}
}
输出:
面积:314.1592653589793
周长:62.83185307179586
面积:50.0
周长:30.0
由于Collection 是一个接口,不能直接实例化。下面的例子是通ArrayList 实现类来调用Collection接口的方法。
package com.test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest {
public static void main(String[] args) {
Collection c = new ArrayList(); // 创建集合c
// 向集合中添加元素
c.add("Apple");
c.add("Banana");
c.add("Pear");
c.add("Orange");
ArrayList array = new ArrayList(); // 创建集合array
// 向集合中添加元素
array.add("Cat");
array.add("Dog");
System.out.println("集合c 的元素个数:" + c.size());
if (!array.isEmpty()) { // 如果array 集合不为空
c.addAll(array); // 将集合array 中的元素添加到集合c 中
}
System.out.println("集合c 中元素个数:" + c.size());
Iterator iterator = c.iterator(); // 返回迭代器iterator。
System.out.println("集合c 中元素:");
while (iterator.hasNext()) { // 判断迭代器中是否存在下一元素
System.out.print(iterator.next() + " "); // 使用迭代器循环输出集合中的元素
}
System.out.println();
if (c.contains("Cat")) { // 判断集合c 中是否包含元素Cat
System.out.println("---集合c 中包含元素Cat---");
}
c.removeAll(array); // 从集合c 中删除集合array 中的所有元素
iterator = c.iterator(); // 返回迭代器对象
System.out.println("集合c 中元素:");
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
// 将集合中的元素存放到字符串数组中
Object[] str = c.toArray();
String s = "";
System.out.println("数组中元素:");
for (int i = 0; i < str.length; i++) {
s = (String) str[i]; // 将对象强制转换为字符串类型
System.out.print(s + " "); // 输出数组元素
}
}
}
输出:
Apple Banana Pear Orange Cat Dog
—集合c 中包含元素Cat—
集合c 中元素:
Apple Banana Pear Orange
数组中元素:
Apple Banana Pear Orange
实现List 接口的容器类中的元素是有顺序的,并且元素可以重复。
ArrayList:
ArrayList 类实现一个可变大小的数组,可以像链表一样被访问。
ArrayList 类常用的构造方法有3 种重载形式,具体如下:
(1)构造一个初始容量为10 的空列表。
public ArrayList()
(2)构造一个指定初始容量的空列表。
public ArrayList(int initialCapacity)
(3)构造一个包含指定集合元素的列表,这些元素是按照该集合的迭代器返回它们的顺序排列。
public ArrayList(Collection c)
package com.test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ArrrayListTest {
public static void main(String[] args) {
ArrayList list = new ArrayList(); // 创建初始容量为10 的空列表
list.add("cat");
list.add("dog");
list.add("pig");
list.add("sheep");
list.add("pig");
System.out.println("---输出集合中的元素---");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
// 替换指定索引处的元素
System.out.println("返回替换集合中索引是1 的元素:" + list.set(1, "mouse"));
iterator = list.iterator();
System.out.println("---元素替换后集合中的元素---");
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
// 获取指定索引处的集合元素
System.out.println("获取集合中索引是2 的元素:" + list.get(2));
System.out.println("集合中第一次出现pig 的索引:" + list.indexOf("pig"));
System.out.println("集合中最后一次出现dog 的索引:" + list.lastIndexOf("dog"));
List l = list.subList(1, 4);
iterator = l.iterator();
System.out.println("---新集合中的元素---");
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
}
}
输出:
cat mouse pig sheep pig
获取集合中索引是2 的元素:pig
集合中第一次出现pig 的索引:2
集合中最后一次出现dog 的索引:-1
—新集合中的元素—
mouse pig sheep
LinkedList类:
LinkedList 实现了List 接口,允许null 元素。LinkedList 类实现一个链表,可以对集合的首部和尾部进行插入和删除操作,相对于ArrayList,LinkedList 在插入或删除元素时提供了更好的性能,但是随机访问元素的速度则相对较慢。
Set 接口是Collection 的子接口,Set 接口没有提供新增的方法。实现Set 接口的容器类中的元素是没有顺序的,并且元素不可以重复,添加的重复元素被覆盖,Set 集合中不允许存在重复元素。
HashSet 类的常用构造方法有3 种重载形式,具体如下:
TreeSet 类:
TreeSet 类不仅继承了Set 接口,还继承了SortedSet 接口,它不允许出现重复元素。由于SortedSet 接口可以对集合中的元素进行自然排序(即升序排序),因此TreeSet 类会对实现了Comparable 接口的类的对象自动排序。
Map 接口是用来存储“键-值”对的集合,存储的“键-值”对是通过键来标识的,所以键不可以重复。
Map 接口的实现类有HashMap 类和TreeMap 类。
HashMap 是基于哈希表的Map 接口的实现类,以“键-值”对“键-值”映射的形式存在。它在HashMap中总是被当做一个整体,系统会根据哈希算法来来计算“键-值”对的存储位置,具有很快的访问速度,最多允许一条记录的键为null,不支持线程同步。可以通过键快速地存取值。
TreeMap 类继承了AbstractMap,可以对键对象进行排序。
package com.test;
import java.util.Iterator;
import java.util.Set;
import java.util.HashMap;
public class HashMapTest {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("101", "一代天骄"); // 添加“键-值”对
map.put("102", "成吉思汗"); // 添加“键-值”对
map.put("103", "只识弯弓射大雕"); // 添加“键-值”对
map.put("104", "俱往矣"); // 添加“键-值”对
map.put("105", "数风流人物"); // 添加“键-值”对
map.put("105", "还看今朝"); // 添加“键-值”对
System.out.println("指定键102 获取值:" + map.get("102"));
Set s = map.keySet(); // 获得HashMap 键的集合
Iterator iterator = s.iterator();
// 获得HashMap 中值的集合并输出
String key = "";
while (iterator.hasNext()) {
key = (String) iterator.next(); // 获得HashMap 键的集合,强制转换为String 型
System.out.println(key + ":" + map.get(key));
}
}
}
输出:
101:一代天骄
102:成吉思汗
103:只识弯弓射大雕
104:俱往矣
105:还看今朝