修饰符、内部类、参数传递
修饰符
final
关键字
final:最终的,不可改变的
-
类:
修饰的类为最终类,不可继承
-
方法:
修饰的方法为最终方法,不可重写
-
变量:
修饰的变量为最终变量,值不能改变
局部变量
成员变量
final关键字用于修饰类
格式:
public final class 类名{
}
JDK
中也存在final
类,如:String
final关键字用于修饰成员方法
【特点】 子类不能重写方法,但是可以使用
final
关键字用于修饰局部变量
【格式】变量定义前加上final关键字
final 变量类型 变量;
【特点】这个局部变量只能赋值一次,后不能改变值
局部变量:引用数据类型,地址不可变,地址对应的内部数据可以发生改变
public class Demo01 {
public static void main(String[] args) {
//局部变量:基本数据类型
final int i1 = 10;
//i1 = 20;
//i1 = 30;
final int i2;
i2 = 100;
//i2 = 200;
//局部变量:引用数据类型,地址不可变,地址对应的内部数据可以发生改变
final int[] arr1 = new int[3];
//arr1 = new int[10]; 使用新数组的地址覆盖原数组arr1的地址
arr1[0] = 100;
arr1[0] = 200;
arr1[0] = 300;
//以上操作没有改变arr1的地址,可以操作
}
}
final
关键字用于修饰成员变量
【格式】修饰符位置加final
修饰符 final 类型 成员变量的名字;
例如:public final String s ="JavaEE";
【特点】不能改变,只能赋值一次,一定要做赋值
赋值方式:
- 直接赋值
- 借助构造方法赋值
public class Student {
public final String s ="JavaEE"; //直接赋值
private final int age;
//借助构造方法赋值,构造方法在对象创建起来只会执行一次
public Student(){
age = 18;
}
public Student(String name, int age) {
this.age = age;
}
//Setter不能用来进行给final成员变量赋值,因为不能保证只执行一次。
//public void setAge(int age) {
// this.age = age;
//}
}
static
关键字的使用
static
关键字:静态
作用:可以用来修饰成员【成员变量,成员方法】,被static
修饰的成员叫做类成员【静态成员】
使用特点:不管修饰什么成员,静态成员被该类的所有对象所共享
1、static修饰成员变量
【格式】修饰符位置加上static
修饰符 static 类型 成员变量;
例如:
public static String className; // 静态变量
访问特点
使用对象访问
类名直接访问【推荐使用】
不管用什么方式访问静态变量,始终访问的是同一个数据。
public class Demo01 {
public static void main(String[] args) {
//非静态变量的使用
Student s1 = new Student();
s1.name = "迪丽热巴";
System.out.println(s1.name);
//静态变量的使用
//1.使用对象访问
System.out.println(s1.className);//null
s1.className = "JavaEE86";
System.out.println("s1.className = " + s1.className);//JavaEE86
Student s2 = new Student();
System.out.println("s2.className = " + s2.className);//JavaEE86
//2.类名直接访问【推荐使用】
System.out.println(Student.className); // JavaEE86
}
}
public class Student {
static String className;//静态变量/类变量
String name;//非静态变量
}
2、static
修饰成员方法
【格式】在方法的修饰符位置加上static,该方法就是静态方法
修饰符 static 返回值类型 方法名(参数列表){}
【使用特点】
-
静态方法所在类的其他类访问
- 对象访问
- 直接使用类名访问【推荐】
public class Demo01 {
public static void main(String[] args) {
//访问非静态方法
Student s1 = new Student();
s1.show2();//非静态方法
//访问静态方法
//1.对象访问
s1.show1();// 静态方法
//2.直接使用类名访问
Student.show1();
}
}
2、静态方法所在类内部使用
静态方法只能访问静态成员。 所以main方法只能访问静态方法
public class Student {
static String className;//静态变量/类变量
String name;//非静态变量
//静态方法
public static void show1() {
System.out.println("这是静态方法");
//静态方法不能访问非静态成员
//System.out.println(name);
//show2();
//只能访问静态成员
System.out.println(className);
show3();
}
public static void show3() {
}
//非静态方法:百无禁忌,都可以访问
public void show2() {
System.out.println("非静态方法");
System.out.println(name);
System.out.println(className);
show1();
show4();
}
public void show4() {
}
}
静态内存分析
静态成员优先于对象而存在
静态代码块
【格式】类中方法外定义的使用static修饰的代码块
static{
//静态代码块
}
【作用】为了给静态变量进行赋值
【特点】随着类的加载而加载一次,会优先于构造方法执行,优先于main方法执行。
/*
静态代码块最先执行,随后main方法执行,
main方法创建对象,构造代码块先执行,然后执行构造方法
*/
public class Student {
static String name;
static {
name = "张三";
System.out.println("静态代码块");
}
{
//会在执行构造方法前执行
System.out.println("构造代码块");
}
public Student() {
System.out.println("构造方法");
}
public static void main(String[] args) {
//main方法
System.out.println("mian方法执行");
new Student();
System.out.println("======");
new Student();
}
}
四种权限修饰符
权限修饰符的作用:控制访问的范围
public | protected | default(空的) 包私有[package-private] | private | |
---|---|---|---|---|
同一类中 | √ | √ | √ | √ |
同一包中(子类与无关类) | √ | √ | √ | X |
不同包的子类 | √ | √ | X | X |
不同包中的无关类 | √ | X | X | X |
访问权限的大小:
public
> proteceted
>defualt
> private
- 修饰类:只能使用public或者default
- 修饰构造方法:一般使用public,方便创建对象。也可以按需使用
- 修饰成员变量:封装使用private,也可以按需使用
- 修饰成员方法:一般使用public,也可按需使用
内部类
内部类的概念分类
内部类:有一个类A内部存在一个类B,这个类B就是内部类,类A就是外部类。
内部类的分类
- 成员内部类:就是在成员位置定义的类
- 局部内部类:在方法内部定义的类
- 匿名内部类:没有类名,一次性使用
成员内部类的定义
【格式】就是在成员位置定义的类
public class 外部类{
class 内部类{
}
}
成员内部类的使用
/*
1.成员内部类所在类中使用
1)内部类访问外部类【Heart访问Person】
在内部类方法中,默认有一个外部类的对象:外部类名.this
如果要访问外部类成员,可以直接使用,外部类名.this.成员
如果局部变量 内部类成员变量 外部类成员变量 名字冲突:
直接访问 this. 外部类名.this.
2)外部类访问内部类【Person访问Heart】
外部类方法中没有成员内部类的默认对象。
如果要访问内部类成员,创建内部类对象,通过对象访问。
2.成员内部类所在类外使用
需要创建内部类的对象
需要借助外部类对象进行创建
格式:
外部类名.内部类类名 对象名 = 外部类对象.new 内部类构造方法();
*/
public class Person { //外部类
private String name;
private String color = "red3";
//构造方法
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void run() {
System.out.println("跑步锻炼身体");
//System.out.println(Heart.this.type);
Heart heart = new Heart("A+");
System.out.println(heart.type);
}
class Heart { // 成员内部类
private String color = "red2";
private String type;
public Heart(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void beats() {
System.out.println("心脏跳动");
//借助默认对象:外部类名.this
System.out.println(Person.this.name);
System.out.println(name);
Person.this.run();
run();
System.out.println("=====");
String color = "red1";
System.out.println(color); //局部变量 red1
System.out.println(this.color);//本类中的成员变量 red2
System.out.println(Person.this.color); //外部类的成员变量 red3
}
}
}
内部类的同名变量访问
如果局部变量 内部类成员变量 外部类成员变量
直接访问 this. 外部类名.this.
局部内部类定义
【格式】在方法中定义的类
修饰符 返回值类型 方法名(参数列表){
class 局部内部类{
}
}
局部内部类的使用及final问题
/*
1.方法使用局部内部类
先创建局部内部类的对象,使用对象访问。创建对象时时,需要先定义类后使用类。
2.局部内部类中访问方法中的变量
1.可以直接访问,只能访问类定义之前的变量。
2.如果局部内部类要访问方法中的变量,要保证该变量是最终的,不可改变的变量。
建议在改变量前加上final关键字。
*/
public class Demo01 {
public static void main(String[] args) {
//System.out.println(i1);
final int i1 = 10; //被局部内部类访问的局部变量,需要是final的变量
System.out.println(i1);
//i1 = 100;
//不能创建内部类对象,需要先定义后使用
//Inner o1 = new Inner();
class Inner {//局部内部类
private int num1 = 10;
public void show() {
System.out.println("num1 = " + num1);
System.out.println("i1 = " + i1);
//System.out.println("i2 = " + i2);
}
}
//可以
Inner o1 = new Inner();
o1.show();
int i2 = 100;
}
}
匿名内部类
【概念】没有类名的内部类
【格式】
匿名内部类的存在,必须具有一个父类或者父接口,【匿名内部类肯定是子类】
new 父类或者父接口(){
//重写父类或者父接口中的方法
};
注意:
1:以上格式是创建了一个对象,这个对象就是匿名子类的对象。
2:还是一个匿名对象
public interface Flyable {
void fly();
}
public class Demo01 {
public static void main(String[] args) {
//有名子类
SuperMan sm = new SuperMan();
sm.fly();
//匿名子类
new Flyable() {
@Override
public void fly() {
System.out.println("不知道什么东东在飞");
}
}.fly();
}
}
匿名内部类的使用
- 结合匿名对象一次性使用
- 一次性调用方法
- 一次性当作实参
- 一次性当作返回值
- 也可以使用有名对象进行接收匿名子类对象
/*
1. 结合匿名对象一次性使用
1. 一次性调用方法
2. 一次性当作实参
3. 一次性当作返回值
2. 也可以使用有名对象进行接收匿名子类对象
*/
public class Demo02 {
public static void main(String[] args) {
//结合匿名对象一次性使用
//1. 一次性调用方法
new Flyable() {
@Override
public void fly() {
System.out.println("Hello fly....");
}
}.fly();
// 2. 一次性当作实参
fly(new SuperMan());
fly(new Flyable() {
@Override
public void fly() {
System.out.println("fly...");
}
});
//3. 一次性当作返回值
System.out.println("========");
//也可以使用有名对象进行接收匿名子类对象
//变量的类型,一定是父类或者父接口的类型 【多态】
Flyable f = new Flyable() {
@Override
public void fly() {
System.out.println("哈哈哈哈");
}
};
f.fly();
}
public static void fly(Flyable f) {
}
public static Flyable getFlyable() {
//return new SuperMan(); //
return new Flyable() {
@Override
public void fly() {
System.out.println("fly。。。。");
}
};
}
}
引用数据类型作为方法的参数
有参数的方法,调用时需要传入实参,实参的类型,个数,顺序要和形参一致。
参数可以是任意类型:
-
基本数据类型
形参改变了,实参不会改变。
-
引用数据类型【传递的是地址值】
当形参的地址没有发生改变时,如果形参内容发生改变,实参也会跟着改变。
【因为形参和实参的地址一样,就是同一个对象】