本人小白一枚,欢迎大家一起讨论学习,如有错误,还望大家指教。
final:代表最终的、不可改变的。既可修饰类、方法、变量(局部变量、成员变量)。
- 被final修饰的类不能被继承。
- 被final修饰的方法不能被重写。
- 被final修饰的变量,不能被重新赋值。
当修饰变量时
1、局部变量–基本类型
基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。
public static void main(String[] args) {
// 以下两种赋值方式都可以
final int num1;
num1 = 10;
final int num2 = 10;
}
2、局部变量–引用类型
引用类型的局部变量,被final修饰后,只能指向一个对象,地址不能更改,但是可以改变对象的成员变量的值。
public void static main(String[] args) {
final User user = new User();
// 创建一个新的对象,赋值给user,无法通过编译
user = new User();
// 可以通过SET方法修改对象的属性
user.setName("张三");
}
3、成员变量
对于成员变量来说,如果使用final关键字修饰,那么这个变量同样无法改变,如同常量一般。
但因为成员变量具有默认值,所以使用final之后必须手动赋值,不会再给默认值了。
成员变量初始化的方式有两种:只能二选一:
- 显示初始化:
final String name = "灰太狼";
- 构造函数初始化:
private final String name;
public Person() {
name = "喜洋洋";
}
注意:上面我们已经提到了,因为成员变量具有默认值,所以我们必须在使用上面的显示初始化或者构造函数初始化,不能像修饰局部变量时,那样赋值。
被final修饰的常量名称,书写规范就是所有字母都用大写。
权限修饰符
Java中提供了四种访问权限,使用不同的访问权限修饰时,被修饰的内容会有不同的访问权限。
- public:共有的
- protected:受保护的
- default:默认的
- private:稀有的
注意:default并不是关键字。
内部类
将一个类定义在另一类里,对里面的类就称为内部类(内置类、嵌套类)。
定义格式:
修饰符 class 外部类名 {
修饰符 class 内部类名 {
//....
}
//....
}
为什么要定义内部类?
类是对我们现实生活中事物的描述,当我们描述事物时,若一个事物内部还包含其他事物,就可以定义内部类。例如,人体类包含心脏类。
内部类分类:
1、成员内部类:定义在类中方法外的类。
2、局部内部类(包含匿名内部类)
访问特点:(不作为重点掌握,但必须了解,可能为面试题)
1、内部类可以直接访问外部类中的成员,包括私有成员。之所以可以直接访问类中的成员,是因为内部类中持有一个外部类的引用,格式:外部类名.this。
2、外部类要访问内部类,必须建立内部类的对象。
访问格式:
当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,直接建立内部类的对象。
格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象;
Outer.Inner inner = new Outer().new Inner();
注意:内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名 和$符号 。比如,Person$Heart.class,所以在我们给类取名时,建议不要使用$符号。
在这里我们总结下上述中提到的问题:
- 编译后产生的.class文件个数:有多少类,就产生多少.class文件。
- 产生.class文件名的规律:外部类名 + $ + 内部类名 + .class。
- 匿名内部类:外部类名 + $ + 数字 + .class。例如:ClassE$1$1.class
class Outside {
private String name = "刘德华";
class Inside {
private String name = "周星驰";
public void method() {
System.out.println(name);
}
class Ininside {
private String name = "周润发";
public void method() {
System.out.println(Outside.this.name);
}
class Inininside {
private String name = "周华健";
public void method() {
System.out.println(name);
}
class $ {
private String name = "$";
public void method() {
System.out.println(name);
}
}
}
}
}
}
public class InsideClassDemo {
public static void main(String[] args) {
Outside.Inside.Ininside.Inininside demo = new Outside().new Inside().new Ininside().new Inininside();
demo.method();
}
}
编译后产生的class文件
public class InsideClassDemo2 {
}
class Fu {}
interface InterfaceDemo {}
class Zi extends Fu implements InterfaceDemo {}
编译后产生的class文件(注意:接口也会编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型)
当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限性。
在外部其他类中,如何直接访问静态内部类的非静态的成员呢?new Outer.Inner().function();
在外部其他类中,如何直接访问静态内部类的静态成员呢?Outer.Inner.function();
注意:当内部类中定义了静态成员,该内部类必须也是static。
当外部类中的静态方法访问内部类时,内部类也必须是静态的。
内部类定义在局部时,注意这三项:
1、不可以被成员修饰符修饰。(public、private、protected、final、static、sychronized、native)
2、可以直接访问外部类中的成员,因为还持有外部类的引用。
3、但是不可以访问它所在的局部中的变量,只能访问final修饰的局部变量。(Java 8中局部变量自动使用final修饰)
4、外部类不能访问局部内部类,只能在方法中访问局部内部类,且访问必须在内部类定义之后。
下面我们介绍下匿名内部类:
1、匿名内部类其实就是内部类的简写格式。
2、定义匿名内部类的前提:内部类必须是继承一个类或者实现接口。
3、匿名内部类的格式:new 父类或者接口名() { //定义子类的内容 }
4、匿名内部类就是匿名子类对象,(是把定义类和创建对象封装成一体),是带有内容的对象。
5、建议匿名内部类定义的方法不要定义太多。
继承一个抽象类
abstract class AbsDemo {
abstract void show();
}
class Outer {
class Inner extends AbsDemo {
@Override
public void show() {
System.out.println("重写show方法!!");
}
}
}
public class AnonymousInnerClass {
public static void main(String[] args) {
new AbsDemo() {
@Override
public void show() {
System.out.println("匿名内部类重写show方法!!");
}
}.show();
Outer.Inner inner = new Outer().new Inner();
inner.show();
}
}
因为匿名内部类没有名字,所以只能使用一次,它通常简化代码的编写。通过上面案例,我们知道继承一个类或者实现接口,最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是实现Runnable接口。