【JAVA语言-第9话】final关键字,static关键字,内部类

目录

内部类 

1.1 内部类 

1.1.1 概述

1.1.2 成员内部类

1.1.2.1 静态内部类

1.1.2.2 非静态内部类

1.1.2.3 静态内部类和非静态内部类的区别

1.2.3.4 案例 (非静态内部类)

1.1.3 局部内部类

1.1.4 匿名内部类

1.1.5 内部类的同名变量访问

1.1.6 权限修饰符

1.1.7 成员变量类型

1.1.8 接口作为方法的参数和返回值

1.2 final关键字

1.2.1 含义

1.2.2 常见用法

1.2.2.1 修饰一个类

1.2.2.2 修饰一个方法

1.2.2.3 修饰一个局部变量

1.2.2.4 修饰一个成员变量

1.3 静态关键字static

1.3.1 概述

1.3.2 使用

1.3.2.1  修饰成员变量

1.3.2.2 修饰成员方法

1.3.3 注意事项

1.3.4 静态代码块


内部类

1.1 内部类 

1.1.1 概述

         如果一个事物的内部包含另一个事物,那么这就是一个类的内部包含另一个类

1.1.2 成员内部类

         在一个类的内部定义一个类,位置和成员变量以及成员方法持平。分为静态内部类和非静态内部类,前者在class前用static修饰。

1.1.2.1 静态内部类

格式

        修饰符 class 外部类名称{

                修饰符 static class 内部类名称{…}      

                …

        }

        

使用:

        外部类名称.内部类名称 对象名 = new 外部类名称.内部类名称();

1.1.2.2 非静态内部类

格式

        修饰符 class 外部类名称{

                修饰符 class 内部类名称{…}      

                …

        }

        

使用:

        外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();

1.1.2.3 静态内部类和非静态内部类的区别
  1. 静态内部类只能访问外部类的静态成员和方法;而非静态内部类可以访问外部类的所有成员和方法,包括静态和非静态的。

  2. 静态内部类的创建不依赖于外部类的实例;而非静态内部类需要通过依赖外部类的实例来创建。

  3. 静态内部类和外部类之间没有直接的引用关系;而非静态内部类可以直接访问外部类的成员。在非静态内部类中,可以使用外部类的引用来访问外部类的成员,例如外部类名.this.成员名。

  4. 静态内部类可以在没有外部类实例的情况下被单独实例化和使用;而非静态内部类必须在外部类的实例上使用

1.2.3.4 案例 (非静态内部类)

例如:有一个学生类对象,在内部有存在一个学生成绩的内部类(统计学生各科的成绩)。这种和每个学生独立捆绑的内部类,只有当学生对象存在的时候才有意义。

源代码: 

package innerClass;

public class Student {
	/**
	 * 姓名
	 */
	String name;
	/**
	 * 年龄
	 */
	int age;
	/**
	 * 性别
	 */
	char sex;
	/**
	 * 年级
	 */
	static String gradeString;
	
	/**
	 * 非静态内部类:封装学生的成绩,只有存在学生对象的时候才有意义,每个对象互不影响。
	 * @author Administrator
	 *
	 */
	public class Score{
		/**
		 * 语文
		 */
		double language;
		/**
		 * 数学
		 */
		double mathematics;
		/**
		 * 英语
		 */
		double english;
		
		public Score(double language,double mathematics,double english) {
			this.language = language;
			this.mathematics = mathematics;
			this.english = english;
		}
		
		/**
		 * 成绩等级
		 */
		public void grade() {
			double average = (language + mathematics + english) / 3;
			if(average >= 85 && average <= 100) {
				System.out.println(name + "的成绩等级为A!");
			}else if(average >= 70 && average < 85) {
				System.out.println(name + "的成绩等级为B!");
			}else if(average >= 60 && average < 70) {
				System.out.println(name + "的成绩等级为C!");
			}else if(average < 60) {
				System.out.println(name + "的成绩等级为D!");
			}
		}
		
		/**
		 * 打印年级
		 */
		public void printGrade() {
			//非静态内部类:可以访问外部类的所有属性和方法,包括静态和非静态
			System.out.println(name + "是" + gradeString + "年级的学生!");
		}
	}

	/**
	 * 主函数:程序入口
	 * @param args
	 */
	public static void main(String[] args) {
		Student student = new Student();
		student.name = "张三";
		//静态属性直接使用 类名.属性名 访问
		Student.gradeString = "高二";
		//因为成绩要在学生对象存在才有意义,所以其实例化必须建立在一个外部类对象的基础之上
		Score score = student.new Score(89.1,94.5,70);
		score.grade();
		score.printGrade();
	}
}

输出结果:

 

1.1.3 局部内部类

        局部内部类指写在方法内部的类,作用域只在当前方法中,出了方法就不能被使用了。

格式:

修饰符 class 外部类名称{

        修饰符 返回值类型 外部类方法名称(参数列表){

                class 局部内部类名称{…}

        }

}

        

使用:就是调用外部类的一个方法。

        外部类 对象名 = new 外部类();  对象名.外部类方法名();

        

注意事项:

        如果希望访问所在方法的局部变量,那么这个局部变量必须是final修饰的,但只要局部变量只赋值一次,那么final关键字可以省略,编译器会默认加上,所以再次赋值会报错。

 原因:

        1.new出来的对象在堆内存当中,局部变量是跟着方法走的,在栈内存当中。

        2.方法运行结束之后,立即出栈,局部变量就会消失,但是new出来的对象会在堆当中持续存在,直到垃圾回收消失,所以比局部变量的生命周期长,必须保证局部变量是唯一不变的。

1.1.4 匿名内部类

        如果接口的实现类(或者父类的子类)只需要使用唯一的一次,那么这种情况下就可以省略掉该类的定义,而改为使用【匿名内部类】。

格式

        接口名称 对象名 = new 接口名称(){

                //覆盖重写所有的抽象方法

        }

        

说明:

        1.new代表创建对象的动作。

        2.接口名称就是匿名内部类需要实现哪个接口(或抽象父类)。

        3.标红区域才是匿名内部类的内容,分号不能少 。  

package innerClass;

/**
 * 匿名内部类:当一个类只是当前使用一次的时候,就可以使用匿名内部类。
 * 	好处:
 * 		可以不用创建实现类,重写方法,然后再用多态的形式调用,节省代码。
 * 	坏处:
 * 		当有多处需要使用到该方法时,每次都要重写该方法,造成代码冗余。
 * 总之,有利有弊,根据不同场景合理使用,方能发挥其最大的作用。
 * @author Administrator
 *
 */
public class AnonymousInnerClass {
	public static void main(String[] args) {
		/**
		 * 匿名内部类,抽象父类形式
		 */
		Animal animal = new Animal() {
			@Override
			public void eat() {
				System.out.println("动物进食!");
			}
		};
		animal.eat();
		
		/**
		 * 匿名内部类,接口形式
		 */
		Pet pet = new Pet() {
			@Override
			public void play() {
				System.out.println("玩耍!");
			}
		};
		pet.play();
	}
}

注意事项:

        1.匿名内部类,在【创建对象】的时候,只能使用唯一的一次。

        2.匿名对象,在【调用方法】时,只能调用唯一的一次。

        3.匿名内部类是省略了【实现类/子类的名称】,但是匿名对象是省略了【对象名称】,匿名内部类和匿名对象不是同一回事。

1.1.5 内部类的同名变量访问

  • 局部变量:变量名;
  • 内部类的成员变量:this.变量名;
  • 外部类的成员变量:外部类名称.this.变量名;

1.1.6 权限修饰符

public > protected > (default) > private

  • 外部类:能用public/(default)修饰。
  • 局部内部类:什么都不能写。
  • 成员内部类:能用public/protected/(default)/private修饰。

1.1.7 成员变量类型

  • 用基本类型作为成员变量类型:private int age;
  • 用类作为成员变量类型:private 自定义类名 变量名;
  • 用接口作为成员变量类型:private 接口名 变量名;

1.1.8 接口作为方法的参数和返回值

Pet.java类 

package innerClass;

public interface Pet{
	/**
	 * 提供setName(String name) 为该宠物命名
	 * @param name
	 */
	public void setName(String name);
	
	/**
	 * 提供 play()方法
	 */
	public void play();
}

Cat.java类 

package innerClass;

/**
 * 定义Cat类,实现Pet接口重写play/setName方法
 */
public class Cat implements Pet{
	/**
	 * 该类必须包含String属性来存宠物的名字。
	 */
	private String name;

	/**
	 * 实现接口的方法
	 */
	@Override
	public void play() {
		System.out.println(" 这只叫 " + name + " 的猫咪正在眨眨眼!");
	}

	/**
	 * 实现接口的方法
	 */
	@Override
	public void setName(String name) {
		this.name = name;
	}
}

测试类: 

package innerClass;

public class ParamsTest {
	
	public static void methodTest(Pet pet) {
		pet.setName("福福");
		pet.play();
	}
	
	public static Pet methodTest2() {
		Pet pet = new Cat();
		pet.setName("年年");
		pet.play();
		return pet;
	}
	
	public static void main(String[] args) {
		System.out.println("接口作为方法参数值:");
		Pet pet = new Cat();
		methodTest(pet);
		
		System.out.println("接口作为方法返回值:");
		Pet pet2 = methodTest2();
	}
}

 输出结果:

1.2 final关键字

1.2.1 含义

         代表最终的、不可改变的。

1.2.2 常见用法

1.2.2.1 修饰一个类

格式

        public final class 类名称{…}

        

含义

        当前这个类不能有任何的子类,但是可以有父类。

        

注意事项

        一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写。

1.2.2.2 修饰一个方法

格式

        修饰符 final 返回值类型 方法名(){…}

        

含义

        当final关键字修饰一个方法的时候,这个方法就是最终方法,也就是不能覆盖重写。

        

注意事项:

        对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。

1.2.2.3 修饰一个局部变量

格式

        final 数据类型 局部变量名;

        

含义

        一旦使用final关键字用来修饰局部变量,那么这个变量就不能进行更改。

        

注意事项

        1.对于基本类型来说,不可变说的是变量当中的数据不可改变

        2.对于引用类型来说,不可变说的是变量当中的地址值不可变,数据可以改变。

1.2.2.4 修饰一个成员变量

格式

        final 数据类型 成员变量名;

        

含义

        对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不变的。

        

注意事项

        1.由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。

        2.对于final的成员变量,有下面两种赋值方式,二者只能选其一。

public class FinalPractice {

	/**
	 * 1.声明变量时赋值
	 */
	private final String name = "Annie";
}
public class FinalPractice {

	private final String name; 
	
	/**
	 * 2.构造方法赋值
	 * @param name
	 */
	public FinalPractice(String name) {
		this.name = name;
	}
}

如果同时采用两种方式,会编译报错。

        3.必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。

1.3 静态关键字static

1.3.1 概述

        static关键字是一个用于声明类成员(变量或方法)的修饰符。它可以与类的静态变量和静态方法一起使用。运用了static关键字,那么这样的内容不再属于对象自己,而是属于类的,所以凡是本类的对象,都共享同一份

1.3.2 使用

1.3.2.1  修饰成员变量

格式:

        private static String initAge;

        

说明:

        1.表示这个变量是一个静态变量,也称为类变量。

        2.静态变量在类被加载时就会被初始化,在整个程序运行过程中,只会有一份拷贝,所有类的实例对象共享同一个静态变量的值。

        

使用:

        1.通过“类名.成员名”的方式访问,例如:Animal.initAge。

        2.通过“对象名.成员名”的方式访问,例如:Animal a = new Animal; a.initAge;。

通常我们都是使用方式一,以便区分静态变量和对象变量。

1.3.2.2 修饰成员方法

格式:

        public static void method(){

        }

        

说明:

        1.表示这个方法是一个静态方法,也称为类方法。

        2.静态方法可以通过类名直接调用,而不需要实例化类对象。

        3.静态方法不能访问非静态的成员变量和方法,只能访问静态变量和方法。

        

使用:

        1.通过“类名.方法名()”的方式访问,例如:Animal.method()。

        2.通过“对象名.方法名()”的方式访问,例如:Animal a = new Animal; a.method();。

通常我们都是使用方式一,以便区分静态方法和对象方法。

1.3.3 注意事项

  • 静态不能直接访问非静态。原因:因为在内存当中是先有的静态方法,后有的非静态方法。 
  • 静态方法当中不能使用this关键字。原因:this代表当前对象,通过谁调用的方法,谁就是当前对象,但是静态方法的访问不用对象,所以就会产生矛盾。 

1.3.4 静态代码块

格式:

        public class 类名称{

                static{

                        静态代码块

                }

        }

        

特点:

        当第一次用到本类时,静态代码块执行的唯一的一次;静态内容总是优先于非静态,所以静态代码块比构造方法先执行。

静态代码块的典型用途:

        用来一次性地对静态成员变量进行赋值。

        

题外话:

        如果文章中存在错误的地方,欢迎大家指正出来,共同学习进步,后续会陆续就JAVA这门课程展开进行分享。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值