final
- 不可改变的
- 修饰类,该类不能拥有子类
- 修饰方法,父类方法有final修饰,子类不能覆盖重写
- 局部变量不能改变
- 引用对象,地址值不能改变,不能new新的对象重新赋值,但可以改变里面的内容
public class FinalDemo2 {
public static void main(String[] args) {
// 创建 User 对象
final User u = new User();
// 创建 另一个 User对象
u = new User(); // 报错,指向了新的对象,地址值改变。
// 调用setName方法
u.setName("张三"); // 可以修改
}
}
如果成员变量是final类型,只能使用以下的两种方法进行赋值
- 直接赋值
public class User {
final String USERNAME = "张三";
private int age;
}
- 使用setter赋值
public class User {
final String USERNAME ;
private int age;
public User(String username, int age) {
this.USERNAME = username;
this.age = age;
}
}
四种权限修饰符
public>protected>(default)不写>private
内部类
应用场景
-
身体和心脏的关系,汽车和发动机的关系(把心脏,发动机拿出来都没用)
-
成员内部类
-
局部内部类,不能使用权限修饰符
//外部类
public class Body {
//成员内部类
public class Heart{
//内部类方法
public void beat(){
System.out.println("心脏跳动");
//可访问外面的
System.out.println("我叫"+name);
}
}
//外部类变量
private String name;
//外部类方法
public void methodBody(){
//局部内部类,前面不能使用过任何修饰
class Inner
{
int num=10;
}
System.out.println("外部类的方法");
//间接使用内部类的方法
new Heart().beat();
}
}
}
使用成员内部类
- 间接调用
public class FinalDemo2 {
public static void main(String[] args) {
Body body=new Body();
//外部方法间接调用内部方法
body.methodBody();
}
}
- 直接调用
public class FinalDemo2 {
public static void main(String[] args) {
//创建内部类对象,直接调用内部类的方法
//外.内 对象名=new wai().nei()
Body.Heart heart=new Body().new Heart();
heart.beat();
}
}
匿名内部类
接口的实现类,只需要使用唯一的一次的时候,使用匿名内部类
接口
public abstract interface FlyAble{
void fly();
}
使用内部类
public class InnerDemo {
public static void main(String[] args) {
/*
1.等号右边:是匿名内部类,定义并创建该接口的子类对象
2.等号左边:是多态赋值,接口类型引用指向子类对象
*/
//匿名内部类,覆盖重写接口的方法,可以采用补充方法的方式, 直接使用接口
FlyAble f = new FlyAble(){
@override
void fly() {
System.out.println("我飞了~~~");
}
};
//调用 fly方法,执行重写后的方法
f.fly();
//匿名对象
new FlyAble(){
@override
void fly() {
System.out.println("我飞了~~~");
}.fly();
}
}
自定义的类作为成员变量类型
定义武器类
class Weapon {
String name; // 武器名称
int hurt; // 伤害值
}
角色类中里面有武器类
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 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();
}
}
interface作为成员变量
定义攻击接口
// 法术攻击
public interface Skill {
public abstract void use();
}
实现攻击
public class SkillIMPL implements Skill {
@override
public void use(){
System.out.println("Biu~Biu");
}
}
定义英雄类
public class Hero{
private String name;
private Skill skill;
public Hero(){}
public Hero(String name,Skill skill)
{
this.name=name;
this.skill=skill;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name=name;
}
public Skill getSkill()
{
return skill;
}
public void setSkill(Skill skill)
{
this.skill=skill;
}
public void attack(){
System.out.println("我叫"+name+"开始释放技能");
//父类(接口),子类都有同名函数,优先使用子类的use(),类比前面学的电脑usb接口的程序
skill.use();
System.out.println("技能释放完成");
}
}
测试类
有三种方法实现skill
- 直接创建新的skill对象
- 创建匿名内部类
public class Test {
public static void main(String[] args) {
Hero hero=new Hero();
hero.setName("aaa");
//向上转型,类比前面学的电脑usb接口的程序
hero.setSkill(new SkillIMPL());
hero.attack();
//创建匿名内部类,直接补充skill里的内容,并赋值到到skill对象里面
Skill skill=new Skill(){
@override
public void use(){
System.out.println("pia-pia");
};
hero.setSkill(skill);
}
hero.attack();
//补充创建skill对象,直接使用匿名对象,只能使用一次
hero.setSkill(new Skill){
@override
public void use(){
System.out.println("pia-pia");
hero.attack();
}
}
}
}
接口作为方法的参数和返回值
其中list是ArrayList的接口
public class DemoInterface{
public static void main(String[] args){
//该用法为多态里面的用法
List<String> list=new ArrayList<>();
List<String> result=addNames(list);
for(int i=0;i<result.size();i++)
{
System.out.println(result.get(i));
}
}
}
//addNames函数
//接口作为方法的参数和返回值
public static List<String> addNames(List<String> list)
{
list.add("a");
list.add("b");
list.add("c");
return list;
}
更加高级的发红包案例
-
所有人都有红包,大家抢完之后,最后一个红包给群主自己
利用现成的代码,还需要补充的地方有三个 -
设置图形界面标题,就是MyRed利用传参构造函数
-
设置群主名称,利用setter
-
设置分发策略,平均or随机
public class Bootstrap{
public static void main(String[] args)
{
//不能直接new接口(抽象类),要使用实现MYRED
//RedPacketFrame frame=new RedPacketFrame();
//使用子类(实现类),接口中只有有参构造方法,要使用有参构造方法
MyRed red=new MyRed("新年红包");
//设置群主名称
red.setOwnerName("aaa");
//设置红包怎么分的方法
//普通红包
OpenMode normal=new NormalMode();
red.setOpenWay(normal);
//手气红包
OpenMode random=new RandomMode();
red.setOpenWay(random);
}
}
接口
public interface OpenMode {
/**
* 请将totalMoney分成count份,保存到ArrayList<Integer>中,返回即可。
*
* @param totalMoney 总金额为方便计算,已经转换为整数,单位为分。
* @param totalCount 红包个数
* @return ArrayList<Integer> 元素为各个红包的金额值,所有元素的值累和等于总金额。
*/
ArrayList<Integer> divide(int totalMoney, int totalCount);
}
普通平均红包的方法
public class NormalMode implements OpenMode {
@Override
public ArrayList<Integer> divide(final int totalMoney, final int totalCount) {
ArrayList<Integer> list = new ArrayList<>();
int avg = totalMoney / totalCount; // 平均值
int mod = totalMoney % totalCount; // 余数,模,零头
// 注意totalCount - 1代表,最后一个先留着
for (int i = 0; i < totalCount - 1; i++) {
list.add(avg);
}
// 有零头,需要放在最后一个红包当中
list.add(avg + mod);
return list;
}
}
随机手气红包
public class RandomMode implements OpenMode {
@Override
public ArrayList<Integer> divide(final int totalMoney, final int totalCount) {
ArrayList<Integer> list = new ArrayList<>();
// 随机分配,有可能多,有可能少。
// 最少1分钱,最多不超过“剩下金额平均数的2倍”
// 第一次发红包,随机范围是0.01元~6.66元
// 第一次发完之后,剩下的至少是3.34元。
// 此时还需要再发2个红包
// 此时的再发范围应该是0.01元~3.34元(取不到右边,剩下0.01)
// 总结一下,范围的【公式】是:1 + random.nextInt(leftMoney / leftCount * 2);
Random r = new Random(); // 首先创建一个随机数生成器
// totalMoney是总金额,totalCount是总份数,不变
// 额外定义两个变量,分别代表剩下多少钱,剩下多少份
int leftMoney = totalMoney;
int leftCount = totalCount;
// 随机发前n-1个,最后一个不需要随机
for (int i = 0; i < totalCount - 1; i++) {
// 按照公式生成随机金额
int money = r.nextInt(leftMoney / leftCount * 2) + 1;
list.add(money); // 将一个随机红包放入集合
leftMoney -= money; // 剩下的金额越发越少
leftCount--; // 剩下还应该再发的红包个数,递减
}
// 最后一个红包不需要随机,直接放进去就得了
list.add(leftMoney);
return list;
}
}
图形界面的实现类
public class MyRed extends RedPacketFrame {
/**
* 构造方法:生成红包界面。
*
* @param title 界面的标题
*/
public MyRed(String title) {
super(title);
}
}