Java基础语法11(final、权限、内部类、引用类型)

java基础语法11(final、权限、内部类、引用类型)

1. fifinal关键字

1.1 概述

学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。那么我们能不能随意的继承API中提供的类,改写其内容呢?显然这是不合适的。为了避免这种随意改写的情况,Java提供了 final 关键字, 用于修饰不可改变内容。

  • final: 不可改变。可以用于修饰类、方法和变量。
    • 类:被修饰的类,不能被继承。
    • 方法:被修饰的方法,不能被重写。
    • 变量:被修饰的变量,不能被重新赋值。

1.2 使用方式

  • 修饰类
    格式如下:
    在这里插入图片描述

查询API发现像 public final class Stringpublic final class Mathpublic final class Scanner 等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。

  • 修饰方法
    格式如下:
    在这里插入图片描述

重写被 final 修饰的方法,编译时就会报错。

  • 修饰变量
  1. 局部变量——基本类型
    基本类型的局部变量,被fifinal修饰后,只能赋值一次,不能再更改。
    代码如下:
public class FinalDemo1 { 
	public static void main(String[] args) { 
		// 声明变量,使用final修饰 
		final int a; 
		// 第一次赋值 
		a = 10; 
		// 第二次赋值 
		a = 20; // 报错,不可重新赋值 
		// 声明变量,直接赋值,使用final修饰 
		final int b = 10; 
		// 第二次赋值 
		b = 20; // 报错,不可重新赋值 
	} 
}

思考,如下两种写法,哪种可以通过编译?

写法1:

final int c = 0; 
for (int i = 0; i < 10; i++) { 
	c = i; 
	System.out.println(c); 
}

写法2:

for (int i = 0; i < 10; i++) { 
	final int c = i; System.out.println(c); 
}
根据 final 的定义,**写法1报错**!写法2,为什么通过编译呢?因为每次循环,都是一次新的变量c。这也是大家 需要注意的地方。 
  1. 局部变量——引用类型
    引用类型的局部变量,被fifinal修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的 修改,代码如下:
public class FinalDemo2 { 
	public static void main(String[] args) { 
		// 创建 User 对象 
		final User u = new User(); 
		// 创建 另一个 User对象 
		u = new User(); // 报错,指向了新的对象,地址值改变。 
		// 调用setName方法 
		u.setName("张三"); // 可以修改 
	} 
}
  1. 成员变量
    成员变量涉及到初始化的问题,初始化方式有两种,只能二选一:

    显示初始化;

public class User { 
	final String USERNAME = "张三"; 
	private int age; 
}

构造方法初始化。

public class User { 
	final String USERNAME ; 
	private int age; 
	public User(String username, int age) { 
		this.USERNAME = username; 
		this.age = age; 
	} 
}
被final修饰的常量名称,一般都有书写规范,所有字母都大写。 

2. 权限修饰符

2.1 概述

在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限

  • public:公共的。
  • protected:受保护的
  • default:默认的
  • private:私有的

2.2 不同权限的访问能力

publicprotecteddefaultprivate
同一类中
同一包中(子类与无关类)
不同包的子类
不同包中的无关类
可见,public具有最大权限。private则是最小权限。 

编写代码时,如果没有特殊的考虑,建议这样使用权限:

  • 成员变量使用 private ,隐藏细节。

  • 构造方法使用 public ,方便创建对象。

  • 成员方法使用 public ,方便调用方法。

      不加权限修饰符,其访问能力与default修饰符相同 
    

3. 内部类

1.1 概述

什么是内部类

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类

成员内部类 :定义在类中方法外的类。

定义格式:
在这里插入图片描述

在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。比如,汽车类 Car 中包含发动机 类 Engine ,这时, Engine 就可以使用内部类来描述,定义在成员位置。
举例:
在这里插入图片描述

访问特点

  • 内部类可以直接访问外部类的成员,包括私有成员。
  • 外部类要访问内部类的成员,必须要建立内部类的对象。

创建内部类对象格式:
在这里插入图片描述

访问演示,代码如下:
定义类:

public class Person { 
	private boolean live = true; 
	class Heart { 
		public void jump() { 
			// 直接访问外部类成员 
			if (live) { 
				System.out.println("心脏在跳动"); 
			} else { 
				System.out.println("心脏不跳了"); 
			} 
		} 
	}
	public boolean isLive() { 
		return live; 
	}
	public void setLive(boolean live) { 
		this.live = live; 
	} 
}

定义测试类:

public class InnerDemo {
	public static void main(String[] args) { 
		// 创建外部类对象 
		Person p = new Person(); 
		// 创建内部类对象 
		Heart heart = p.new Heart(); 
		// 调用内部类方法 
		heart.jump(); 
		// 调用外部类方法 
		p.setLive(false); 
		// 调用内部类方法 
		heart.jump(); 
	} 
}
输出结果: 
心脏在跳动 
心脏不跳了 
内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名 和$符号 。 比如,Person$Heart.class

1.2 匿名内部类【重点】

匿名内部类 :是内部类的简化写法。它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象。 开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作,

  1. 定义子类
  2. 重写接口中的方法
  3. 创建子类对象
  4. 调用重写后的方法

我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快 捷方式。

前提

匿名内部类必须继承一个父类或者实现一个父接口。

格式
在这里插入图片描述

使用方式

以接口为例,匿名内部类的使用,
代码如下:
定义接口:

public abstract class FlyAble{
	public abstract void fly(); 
}

创建匿名内部类,并调用:

public class InnerDemo { 
	public static void main(String[] args) { 
		/*1.等号右边:是匿名内部类,定义并创建该接口的子类对象 
		2.等号左边:是多态赋值,接口类型引用指向子类对象 
		*/
		FlyAble f = new FlyAble(){ 
			public void fly() { 
				System.out.println("我飞了~~~"); 
			} 
		};
		//调用 fly方法,执行重写后的方法 
		f.fly(); 
	} 
}

通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:

public class InnerDemo2 { 
	public static void main(String[] args) { 
		/*1.等号右边:定义并创建该接口的子类对象 
		2.等号左边:是多态,接口类型引用指向子类对象 
		*/
		FlyAble f = new FlyAble(){ 
			public void fly() { 
				System.out.println("我飞了~~~"); 
			} 
		};
		// 将f传递给showFly方法中 
		showFly(f); 
	}
	public static void showFly(FlyAble f) {
		f.fly(); 
	} 
}

以上两步,也可以简化为一步,代码如下:

public class InnerDemo3 { 
	public static void main(String[] args) { 
		/*创建匿名内部类,直接传递给showFly(FlyAble f) */
		showFly( new FlyAble(){ 
			public void fly() { 
				System.out.println("我飞了~~~"); 
			} 
		}); 
	}
	public static void showFly(FlyAble f) { 
		f.fly(); 
	} 
}

4. 引用类型用法总结

实际的开发中,引用类型的使用非常重要,也是非常普遍的。我们可以在理解基本类型的使用方式基础上,进一步 去掌握引用类型的使用方式。基本类型可以作为成员变量、作为方法的参数、作为方法的返回值,那么当然引用类 型也是可以的。

4.1 class作为成员变量

在定义一个类Role(游戏角色)时,代码如下:

class Role { 
	int id; // 角色id 
	int blood; // 生命值 
	String name; // 角色名称 
}

使用 int 类型表示 角色id和生命值,使用 String 类型表示姓名。此时, String 本身就是引用类型,由于使用 的方式类似常量,所以往往忽略了它是引用类型的存在。如果我们继续丰富这个类的定义,给 Role 增加武器,穿 戴装备等属性,我们将如何编写呢?
定义武器类,将增加攻击能力:

class Weapon { 
	String name; // 武器名称 
	int hurt; // 伤害值 
}

定义穿戴盔甲类,将增加防御能力,也就是提升生命值:

class Armour { 
	String name;// 装备名称 
	int protect;// 防御值 
}

定义角色类:

class Role { 
	int id; 
	int blood; 
	String name; 
	// 添加武器属性 
	Weapon wp; 
	// 添加盔甲属性 
	Armour ar; 
	// 提供get/set方法 
	public Weapon getWp() { return wp; }
	public void setWeapon(Weapon wp) { this.wp = wp; }
	public Armour getArmour() { return ar; }
	public void setArmour(Armour ar) { this.ar = ar; }
	// 攻击方法 
	public void attack(){ 
		System.out.println("使用"+ wp.getName() +", 造成"+wp.getHurt()+"点伤害"); 
	}
	// 穿戴盔甲 
	public void wear(){ 
		// 增加防御,就是增加blood值 
		this.blood += ar.getProtect(); 
		System.out.println("穿上"+ar.getName()+", 生命值增加"+ar.getProtect()); 
	} 
}

测试类:

public class Test { 
	public static void main(String[] args) { 
		// 创建Weapon 对象 
		Weapon wp = new Weapon("屠龙刀" , 999999); 
		// 创建Armour 对象 
		Armour ar = new Armour("麒麟甲",10000); 
		// 创建Role 对象 
		Role r = new Role(); 
		// 设置武器属性 
		r.setWeapon(wp); 
		// 设置盔甲属性 
		r.setArmour(ar); 
		// 攻击 
		r.attack(); 
		// 穿戴盔甲 
		r.wear(); 
	} 
}
输出结果: 
使用屠龙刀,造成999999点伤害 
穿上麒麟甲 ,生命值增加10000 
类作为成员变量时,对它进行赋值的操作,实际上,是赋给它该类的一个对象。 

4.2 interface作为成员变量

接口是对方法的封装,对应游戏当中,可以看作是扩展游戏角色的技能。所以,如果想扩展更强大技能,我们在 Role 中,可以增加接口作为成员变量,来设置不同的技能。

4.3 interface作为方法参数和返回值类型

当接口作为方法的参数时,需要传递什么呢?当接口作为方法的返回值类型时,需要返回什么呢?对,其实都是它的 子类对象。 ArrayList 类我们并不陌生,查看API我们发现,实际上,它是 java.util.List 接口的实现类。所 以,当我们看见 List 接口作为参数或者返回值类型时,当然可以将 ArrayList 的对象进行传递或返回。

请观察如下方法:获取某集合中所有的偶数。

定义方法:

public static List<Integer> getEvenNum(List<Integer> list) { 
	// 创建保存偶数的集合 
	ArrayList<Integer> evenList = new ArrayList<>(); 
	// 遍历集合list,判断元素为偶数,就添加到evenList中 
	for (int i = 0; i < list.size(); i++) { 
		Integer integer = list.get(i); 
		if (integer % 2 == 0) { 
			evenList.add(integer); 
		} 
	}
	/*返回偶数集合因为getEvenNum方法的返回值类型是List,
	而ArrayList是List的子类, 所以evenList可以返回 */
	return evenList; 
}

调用方法:

public class Test { 
	public static void main(String[] args) { 
		// 创建ArrayList集合,并添加数字 
		ArrayList<Integer> srcList = new ArrayList<>(); 
		for (int i = 0; i < 10; i++) { 
			srcList.add(i); 
		}
		/*获取偶数集合 因为getEvenNum方法的参数是List,
		而ArrayList是List的子类, 所以srcList可以传递 */
		List list = getEvenNum(srcList); 
		System.out.println(list); 
	} 
}
接口作为参数时,传递它的子类对象。 
接口作为返回值类型时,返回它的子类对象。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 基础核心总结》 Java 概述 什么是 Java2 Java 的特点Java 开发环境 JDK JRE Java 开发环境配置 Java 基本语法 数据类型基础语法运算符 Java 执行控制流程条件语句 if 条件语句 if...else 条件语句if...else if 多分支语句switch 多分支语句 循环语句 while 循环语句do...while 循环for 循环语句 跳转语句 break 语句 continue 语句面向对象 类也是-种对象对象的创建 属性和方法 构造方法 方法重载 方法的重写 初始化 类的初始化 成员初始化 构造器初始化初始化顺序 数组初始化 对象的销毁 对象作用域 this 和 super 访问控制权限继承 多态组合代理 向上转型static final 接口和抽象类接口 抽象类异常 认 识 Exception 什么是 Throwable 常见的 Exception 与 Exception 有关的 Java 关键字 throws 和 throw try 、finally 、catch 什么是 Error 内部类 创建内部类集合 Iterable 接口顶层接口 ArrayList Vector LinkedList 类Stack HashSet TreeSet LinkedHashSet 类 PriorityQueue HashMap TreeMap 类 LinkedHashMap 类 Hashtable 类IdentityHashMap 类WeakHashMap 类 Collections 类集合实现类特征图 泛形 泛型的使用 用泛型表示类 用泛型表示接口泛型方法 泛型通配符 反射 Class 类Field 类Method 类ClassLoader 类 枚举 枚举特性 枚举和普通类-样枚举神秘之处 枚举类 I/O File 类 基础 IO 类和相关方法InputStream OutputStream Reader 类Writer 类 InputStream 及其子类 OutputStream 及其子类Reader 及其子类Writer 及其子类 注解 关于 null 的几种处理方式大小写敏感 null 是任何引用类型的初始值 null 只是-种特殊的值使用 Null-Safe 方法null 判断 关于思维导图 Java.IO Java.lang Java.math Java.net Java 基础核心总结 V2.0 IO 传统的 BIO BIO NIO 和 AIO 的区别什么是流 流的分类 节点流和处理流 Java IO 的核心类 File Java IO 流对象 字节流对象InputStream OutputStream 字符流对象Reader Writer 字节流与字符流的转换新潮的 NIO 缓冲区(Buffer)通道(Channel) 示例:文件拷贝案例 BIO 和 NIO 拷贝文件的区别操作系统的零拷贝 选择器(Selectors) 选择键(SelectionKey) 示例:简易的客户端服务器通信 集合 集合框架总览 -、Iterator Iterable ListIterator 二、Map 和 Collection 接口Map 集合体系详解 HashMap LinkedHashMap TreeMap WeakHashMap Hashtable Collection 集合体系详解 Set 接口 AbstractSet 抽象类SortedSet 接口HashSet LinkedHashSet TreeSet List 接口 AbstractList 和 AbstractSequentialList Vector Stack ArrayList LinkedList Queue接口Deque 接口 AbstractQueue 抽象类LinkedList ArrayDeque PriorityQueue 反射的思想及作用 反射的基本使用 获取类的 Class 对象构造类的实例化对象获取-个类的所有信息 获取类中的变量(Field) 获取类中的方法(Method) 获取类的构造器(Constructor) 获取注解 通过反射调用方法反射的应用场景 Spring 的 IOC 容器反射 + 抽象工厂模式 JDBC 加载数据库驱动类反射的优势及缺陷 增加程序的灵活性破坏类的封装性 性能损耗 代理模式 静态代理与动态代理常见的动态代理实现JDK Proxy CGLIB JDK Proxy 和 CGLIB 的对比动态代理的实际应用 Spring AOP 变量 变量汇总实例变量 实例变量的特点全局变量 静态变量 静态变量的特点类变量 局部变量

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值