Java面向对象笔记 • 【第8章 内部类和泛型】
全部章节 >>>>
本章目录
8.1 内部类
8.1.1 内部类概述
- 为实现程序设计的需要,需要将一个类放在另一个类的内部定义,定义在其他类内部的类就称为内部类,包含内部类的类也被称为外部类,内部类的作用如下:
- 内部类提供了更好的封装,可以将内部类隐藏在外部类内,不允许同一个包中的其他类访问该类。
- 内部类成员可以直接访问外部类的私有数据,因为内部类作为其外部类成员,同一个类的成员之间可以相互访问。但外部类不能访问内部类的实现细节,如内部类的成员变量。
- 匿名内部类适用于创建那些仅需要一次使用的类。
8.1.2 内部类使用
语法:
public class OutClass{
……
//定义内部类
public class innerClass{
}
}
内部类分为两种:静态内部类和非静态内部类,使用static修饰的内部类称为静态内部类,没有使用static修饰的内部类则称为非静态内部类。
8.1.3 实践练习
8.2 静态内部类
8.2.1 静态内部类的实现
- 使用static修饰的内部类,被称为静态内部类,静态内部类属于外部类本身,而不属于外部类的某个对象。
- 静态内部类可以包含静态成员,也可以包含非静态成员。
- 依据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态内部类的实例方法,也不能访问外部类的实例成员,只能访问外部类的静态成员。
示例: 演示静态内部类的定义
public class OutClass {
private int outPro=5;
private static int outPro2=9;
private static class InnerClass{
private static int innerPro=10;//静态内部类中可以定义静态成员
private int innerPro2=100;//静态内部类中的实例属性
public void accessOutPro(){
/*以下代码在编译时出现错误静态内部类无法直接访问外部类的实例成员*/
//System.out.println(outPro);
//可通过外部类实例访问外部类实例属性
System.out.println("外部类实例属性outPro="+new OutClass().outPro);
//访问外部类的静态成员,代码正确
System.out.println("外部类的静态属性outPro2="+outPro2);
}
}
//未完接下一页
}
public class OutClass {
//接上一页
public void accessInnerPro(){
//System.out.println(innerPro);
//以上代码出现错误,应修改为如下形式,即通过类名访问静态内部类的类成员
System.out.println("内部类的静态属性innerPro="+InnerClass.innerPro);
//System.out.println(innerPro2);
//以上代码出现错误,应修改为如下格式
InnerClass ic=new InnerClass();
System.out.println("内部类实例属性innerPro2="+ic.innerPro2);
ic.accessOutPro();//调用静态内部类的实例方法
}
public static void main(String[] args) {
OutClass oc=new OutClass();
oc.accessInnerPro();
}
}
8.2.2 实践练习
8.3 匿名内部类
8.3.1 匿名内部类的实现
匿名内部类适用于仅需要一次使用的类,匿名内部类的语法较为特别,创建匿名内部类时,会立即创建一个该类的实例,创建完毕之后该类的定义会立即消失。
如果匿名内部类需要访问外部类的局部变量,则必须使用final修饰符修饰外部类的局部变量,否则系统将报错。
语法:
new 父类构造器(参数列表)| 实现接口(){
//匿名内部类的类体部分
}
匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。
提醒:匿名内部类的两条规则
- 匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象,因此不允许将匿名内部类定义成抽象类。
- 匿名内部类不能定义构造器,因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义实例化初始块,通过实例化初始块来完成构造器需要完成的事情。
示例: 演示匿名内部类的定义
//匿名内部类需要实现的接口
public interface Product {
double getPrice();
String getName();
}
public class Anonymous {
public void execute(Product product){
System.out.println("购买了一个:"+product.getName()+" 花费:"+product.getPrice());
}
public static void main(String[] args) {
Anonymous aym=new Anonymous();
/*调用execute()方法时,需要创建一个Product类型参数,此处传入匿名实现类的实例*/
aym.execute(new Product() {
public double getPrice() {
return 98.29;
}
public String getName() {
return "费列罗巧克力";
}
});
}
}
示例:将匿名内部类更改为内部类
public class Consumer {
public void execute(Product product){
System.out.println("购买了一个:"+product.getName()+" 花费:"+product.getPrice());
}
public class MyProduct implements Product{ //内部类
public double getPrice() {
return 98.29;
}
public String getName() {
return "费列罗巧克力";
}
}
public static void main(String[] args) {
Consumer consumer = new Consumer(); //实例化一个外部类对象
//通过外部类对象创建内部类对象
Product product = consumer.new MyProduct();
consumer.execute(product);
}
}
8.3.2 实践练习
8.4 泛型
8.4.1 泛型概述
没有使用泛型时取出集合元素
List listUser = new ArrayList();
listUser.add(new User(“张三”,20)) ;
User user = (User)listUser.get(0) ; //使用了强制类型转换。
使用泛型时取出集合元素
List<User> listUser = new ArrayList<User>();
listUser.add(new User(“张三”,20)) ;
User user = listUser.get(0) ; //把类型转换交给了编译器
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
泛型的原理就是参数化类型
- 泛型把类型看做参数,也就是说把所要操作的数据类型看做参数,就像方法的形式参数是运行时传递的值的占位符一样。
- 泛型中的类型变量扮演的角色就如同一个参数,它提供给编译器用来类型检查的信息。
泛型的分类
- 泛型类
- 泛型方法
8.4.2 泛型应用
1、泛型类:就是具有一个或多个类型变量的类。
示例: 定义泛型类并实例化泛型类
public classPair<T>{
private T first
public Pair(T first){this.first=first;}
public void setFirst(T newValue){first=newValue;}
public T getFirst(){return first;}
}
public class PairTest{
public static void main(String[] args){
//用具体的类型替换类型变量就可以实例化泛型类型
Pair<String> pair=new Pair<String>("Hello");
System.out.println("first="+pair.getFirst());
}
}
2、泛型方法:
- 带有参数类型的方法即泛型方法,泛型方法使得该方法能够独立于类而产生变化。
- 泛型方法所在的类可以是泛型类,也可以不是泛型类。
示例:声明一个f(T x)泛型方法,用于返回调用该方法时,所传入的参数类型的类名
class GenericMethod{
//T是泛型类型参数
public <T> void f(T x){
System.out.println(x.getClass().getName());
}
}
public class GenericMethodTest{
public static void main(String[] args){
GenericMethod gm=new GenericMethod();
gm.f(" ");
gm.f(1);
gm.f(1.0f);
gm.f('c');
gm.f(gm);
}
}
3、泛型定义:泛型定义包括泛型类定义和泛型对象定义,其中泛型对象定义的应用最为普遍。
语法:
类名称<具体类> 对象名称 = new 类名称<具体类>();
例如:
List<String> citys = new ArrayList<String>(); //城市列表
List<Address> empAdds = new ArrayList<Address>(); //员工住址列表
Map<String, Emp> empnoToEmp = new HashMap<String, Emp>(); //员工编号到员工映射
示例: 泛型集合List<T>与Map<K,V>应用
List<String> strList=new ArrayList<String>(); //声明泛型集合,该集合元素为String类型
//strList集合中只能添加字符串元素,否则无法通过编译
strList.add("apple");
strList.add("peer");
strList.add("banana");
//strList.add(new Date());此处如果不将其注释,在编译时系统报错
//集合使用泛型后,从集合中获取数据无须强制类型转换
String str=strList.get(strList.size()-1);
//创建Map泛型集合,map的Key为String类型,value为Date类型
Map<String,Date> map=new HashMap<String,Date>();
//向集合中添加数据
map.put("Java", new Date(60000));
map.put("C#", new Date(300000000));
map.put("MySQL", new Date(1000000));
//调用keySet()方法返回装有所有Key值的Set集合
Set<String> keySet=map.keySet();
//通过keySet获取Iterator迭代器
Iterator<String> iter=keySet.iterator();
while(iter.hasNext()){//遍历迭代器
String key=iter.next();
System.out.println("Map["+key+"]="+map.get(key));
}
8.4.3 实践练习
总结:
- 内部类提供了更好的封装,可以将内部类隐藏在外部类内。内部类成员可以直接访问外部类的私有数据,但外部类不能访问内部类的成员变量。
- 使用static修饰的内部类,被称为静态内部类,静态内部类属于外部类本身,而不属于外部类的某个对象。
- 匿名内部类适用于创建那些仅需要一次使用的类,匿名内部类不能是抽象类,不能定义构造器,但是可以通过实例化初始块来完成构造器需要完成的事情。
- 泛型的原理就是参数化类型,泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
本文来自博客园,作者:明金同学,转载请注明原文链接:https://www.cnblogs.com/vmuu/p/15663570.html
公众号:【明金同学】