1.final关键字
final:不可改变你,可以用于修饰类、方法和变量(final用于修饰不可改变的内容)
- 类:被修饰的类,不能被继承
- 方法:被修饰打的方法不能被重写
- 变量:被修饰的变量,不能被重新赋值
使用方式:
修饰类(格式):
final class 类名{
}
修饰方法(格式):
修饰符 final 返回值类型 方法名 (参数列表){
//方法体
} //重写被final修饰的方法,编译时就会报错
修饰变量
1.局部变量---基本类型
public static Demo01{
public static void main(){
//声明变量,使用final修饰
final int a;
//第一次赋值
a = 10;
//第二次赋值
a = 20; //报错,不可重新赋值
//声明变量,直接赋值,使用final修饰
final int b = 10;
//第二次赋值
b = 20; // 报错,不可重新赋值
}
}
我们可以考虑下面这种情况:
//写法一
final int c = 0;
for(int i = 0; i < 10; i++){
c=i;
System.out.println(c);
}
//写法二
for(int i = 0;i < 10; I++){
final int c = i;
System.out.println(c);
}
// 根据final的定义,写法1报错!写法2能通过编译的原因是:每次循环,都是一个新的变量c
2.局部变量---引用类型
引用类型的局部变量,被final修饰后,只能指向一个对象,地址不能再改。但是不影响对象内部的成员变量值的修改,代码如下:
public class Demo02{
public static void main (String[] args){
//创建User对象
final User u = new User();
//创建 另一个 User对象
u = new User(); //报错,指向了新的对象,地址值改变
//调用setName方法
u.setName("张三"); //可以修改
}
}
3.成员变量
成员变量涉及到初始化的问题,初始化方式有两种,只能二选一:
- 显示初始化
public class User{
final String USERNAME = "张三";
private int age;
}
- 构造方法初始化
public class User {
final String USERNAME;
private int age;
pubic User(String name, int age){
this.USERNAME = username;
this.age = age;
}
}
在这里我们要注意:被final修饰的常量名称,所有字母都要大写;
2.权限修饰符
java中一般提供四类访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限
- public:公共的
- protected:受保护的
- default:默认的
- private:私有的
public | protected | default(空的) | private | |
同一类中 |
√ | √ | √ | √ |
同一包中(子类与无关类) | √ | √ | √ | |
不同包的子类 | √ | √ | ||
不同包中的无关类 | √ |
从上表可以看出。public具有最大的访问权限,private则是最小权限
在编写代码的时候。如果没有特殊的考虑,一般建议这样使用权限:
- 成员变量使用private,隐藏细节
- 构造方法使用public,方便创建对象
- 成员方法使用public,方便调用方法不加权限修饰符,其访问能力与default修饰符相同
3.内部类
将一个类A定义在另一个类B的中,里面的那个类A就称为内部类,B则成为外部类
成员内部类:定义在类中方法外的类,格式为:
class 外部类{
class 内部类{
}
}
如果我们在描述一个事物的时候,这个事物还包含了其他事物,我们就可以使用内部类这种结构
代码举例:
class Car{ //外部类
class Engine{ //内部类
}
}
访问特点:
- 内部类可以直接访问外部类的成员,包括私有成员
- 外部类要访问内部类的成员,必须要创建内部类的对象
创建内部类对象的格式:
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
演示代码如下:
//定义类
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 = new Heart();
//调用内部类方法
heart.jump(); //心脏在跳动
//调用外部类对象
p.setLive(false);
//调用内部类方法
heart.jump(); //心脏不跳了
}
}
内部类仍然是一个独立的类,在编译后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,例如: Person$Heart.class
匿名内部类【重点】
匿名内部类:是内部类的简化写法,其本质为一个[带具体实现的][父类或者父类接口的][匿名的]子类对象
前提:匿名内部类必须继承一个父类或者实现一个接口
new 父类名或者接口名(){
//方法重写
@Override
public void method(){
//执行语句
}
};
使用方式,以接口为例:
//定义接口
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 static void main(){
/*
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 InnerDemo03{
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();
}
}
引用类型用法总结
class作为成员变量
在定义一个类Role(游戏角色)时,代码如下:
class Role{
int id;
int blood;
String name;
}
//定义武器类
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 attack(){
System.out.println("使用"+ wp.getName()+",造成"+wp.getHurt()+"点伤害");
}
//穿戴盔甲
public void wear(){
this.blood += ar.getProtect();
System.out.println("穿上"+ ar.getName()+",生命值增加"+ar.getProtect())
}
}
//测试类
public class Test{
public static void main(){
//创建Weapon对象
Weapon wp = new Weapon("屠龙刀",99999);
//创建Armour对象
Armour ar = new Armour("麒麟甲",10000);
//创建Role对象
Role r = new Role();
//设置武器属性
r.setWeapon(wp);//使用屠龙刀,造成99999点伤害
//设置盔甲属性
r.wear(); //穿上麒麟甲,生命值增加10000
}
}
interface作为成员变量
接口是对方法的封装
//法术进攻
public interface FaShuSkill {
public abstract void faShuAttack();
}
//定义角色类
public class Role{
FaShuSkill fs;
public void setFaShuSkill(FaShuSkill fs){
this.fs = fs;
}
//法术攻击
public void faShuSkillAttack(){
System.out.println("发动法术攻击");
fs. faShuAttack();
System.out.println("攻击完毕");
}
}
//定义测试类
public class Test {
public static void main(){
//创建游戏角色
Role role = new Role();
//设置角色法术技能
role.setFaShuSkill(new FaShuSkill()){
@Override
public void faShuAttack(){
System.out.println("纵横天下");
}
});
//发动法术攻击
role.faShuSkillAttack();
//更换技能
role。setfaShuSkill(new FaShuSkill()){
@Override
public void faShuAtttack(){
System.out.println("逆转乾坤");
}
});
role.faShuSkillAttack();
}
}
输出结果:
发动法术攻击:纵横天下
攻击完毕
发动法术攻击
攻击完毕
interface作为方法的参数和返回值类型
我们在看见list接口作为参数或者返回值类型时,可以将ArrayList的对象进行传递或返回
//获取某集合中的所有的偶数
//定义方法
public static list<Integer> getEverNum(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 static 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,而ArrayLis是list的子类,所以srcList可以传递
List list = getEvenNum(srcList);
System.out.println(list);
}
}