目录
(2.1)推荐用类名.静态成员变量来访问静态成员变量。可以把静态成员变量理解为描述class本身的成员变量(非实例成员变量)。
(1)定义:用static修饰的方法称为静态方法。调用实例方法必须通过一个实例对象,而调用静态方法则不需要实例对象,通过类名就可以调用。
(2.1)静态方法属于class类级别的,而不属于实例对象。因此,静态方法内部,无法访问this变量,也无法访问实例对象的成员变量;
(2.2)静态方法只能访问静态成员变量或静态方法;普通方法内部,也可以访问静态成员变量或静态方法;
(2.4)静态方法也经常用于辅助方法。注意到Java程序的入口main()也是静态方法。
(2)静态方法: interface接口中也可以有静态方法,只能使用接口名称直接调用。
(3.1)接口中的默认方法,必须使用“接口实现类”的对象,才能调用。
(3.2)接口中的静态方法,必须通过“接口名.方法名()”才能进行调用。
(2.1)如果有些代码逻辑或对象,需要在项目启动的时候就执行或创建,这时候就需要静态代码块。比如一个项目启动需要加载的很多配置文件或者数据库连接池对象等,我们就可以都放入静态代码块中。
(2.2)静态代码块中,只允许调用静态方法或静态的成员变量,不允许调用普通方法或普通成员变量。
(3) 执行顺序:静态代码块 > 构造代码块 > 构造函数 > 普通代码块
(1)使用static关键字修饰的成员变量,被称为静态成员变量,它属于所有实例“共享”的成员变量。
(3)静态方法或静态成员变量,建议通过类名进行访问。(不推荐使用实例对象访问)
(4)静态方法只能可以调用静态的方法或成员变量,不能调用普通的方法或成员变量。静态方法无法访问this。
(5)使用static修饰的代码块,被称为静态代码块。在静态代码块在“类被加载”的时候运行,而且只运行一次。
(6)静态代码块中,只允许调用静态方法或静态的成员变量,不允许调用普通方法或普通成员变量。
(7)执行流程:静态代码块 > 构造代码块 > 构造函数 > 普通代码块。
(8)如果存在继承关系,则执行流程为:先“静态”(父类 > 子类),再“非静态”(父类 > 子类
2、包作用域:位于同一个包的类,可以访问包作用域的字段和方法。不用public、protected、private修饰的字段和方法就是包作用域。例如,Person类定义在hello包下面:
(2)用import语句,导入小军的Arrays,然后写简单类名:
(3)使用import static的语法,它可以导入一个类的静态字段和静态方法:
1、friendly(默认访问修饰符): 在同一包内可见,不使用任何修饰符。使用位置:类、接口、变量、方法。
2、private(私有访问修饰符) : 在同一类的内部可见。使用位置:变量、方法。
3、public (公共访问修饰符): 对所有类可见。使用位置:类、接口、变量、方法
4、protected(保护访问修饰符) : 对同一包内的类、或子类(子类可以不同包)可见。使用位置:变量、方法。
5、局部变量:在方法内部定义的变量称为局部变量,局部变量作用域从变量声明处开始到对应的块结束。方法参数也是局部变量。
6、final 修饰符:Java还提供了一个final修饰符。final与访问权限不冲突,它有很多作用。用final修饰class可以阻止被继承,修饰的变量为常量,修饰的方法不可被重写
1、普通内部类:如果一个类定义在另一个类的内部,这个类就是Inner Class:
(2)普通内部类可以访问外部类的所有成员变量和成员方法(包括私有的)
(4)内部类通过外部类名.this.成员变量(成员方法)访问成员变量(成员方法)
(6)Java编译器编译后的.class文件可以发现,Outer类被编译为Outer.class,而Inner类被编译为Outer$Inner.class。
(1)静态内部类不能访问外部类的非静态的成员变量 , 也不能出现Outer.this
一、static 关键字
1. static 静态成员变量:
(1)定义: 在一个class
类中定义的成员变量,我们称之为实例成员变量(成员变量)。实例成员变量的特点是,每个实例都有独立的成员变量,各个实例的同名成员变量互不影响。除此以外,还有一种成员变量,是使用static
关键字修饰的成员变量,称为静态成员变量,静态成员变量所有实例都共享空间 :
class Person {
public String name;
public int age;
// 定义静态成员变量number:
public static int number;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Main {
public static void main(String[] args) {
Person ming = new Person("Xiao Ming", 12);
Person hong = new Person("Xiao Hong", 15);
ming.number = 88;
hong.number = 99;
System.out.println(hong.number); //99
System.out.println(ming.number); //99
}
}
对于静态成员变量,无论修改哪个实例的静态成员变量,都是访问相同的内存空间:所有实例的静员态成员变量都被修改了,原因是静态成员变量并不属于实例。
(2)使用静态成员变量:
(2.1)推荐用类名.静态成员变量来访问静态成员变量。可以把静态成员变量理解为描述class
本身的成员变量(非实例成员变量)。
(2.2)不推荐用实例变量.静态成员变量去访问静态成员变量。因为在Java程序中,实例对象并没有静态成员变量。在代码中,实例对象能访问静态成员变量只是因为编译器可以根据实例类型自动转换为类名.静态成员变量来访问静态对象
2. static 静态方法:
(1)定义:用static
修饰的方法称为静态方法。调用实例方法必须通过一个实例对象,而调用静态方法则不需要实例对象,通过类名就可以调用。
(2)注意事项:
(2.1)静态方法属于class
类级别的,而不属于实例对象。因此,静态方法内部,无法访问this
变量,也无法访问实例对象的成员变量;
(2.2)静态方法只能访问静态成员变量或静态方法;普通方法内部,也可以访问静态成员变量或静态方法;
(2.3)通过实例变量也可以调用静态方法或静态成员变量(这只是编译器自动帮我们把实例改写成类名而已),不推荐使用。所以,通常情况下,通过实例变量访问静态成员变量和静态方法,会得到一个编译警告;静态方法经常用于工具类。例如
-
Arrays.sort()
-
Math.random()
(2.4)静态方法也经常用于辅助方法。注意到Java程序的入口main()
也是静态方法。
package com.yuan.staticClass;
//static 修饰的成员变量为静态成员变量,所有实例都共享空间;
public class Student {
public String name;
public int age;
//不使用静态成员变量
// public String schoolName;
//使用静态成员变量
public static String schoolName;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name, int age, String schoolName) {
this.name = name;
this.age = age;
Student.schoolName = schoolName; //推荐使用类名.静态成员变量名
}
//静态方法:
public static void eat(){
System.out.println("这个是静态方法 eat方法");
System.out.println(schoolName+"的学生正在吃");
todo();//静态方法只能调用静态方法和静态成员变量
//test() //不能调用普通方法
}
public static void todo(){
System.out.println("这个是静态todo方法");
}
//普通方法: 普通方法可以调用静态方法和静态成员变量
public void test(){
eat();
todo();
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Test{
public static void main(String[] args) {
//不使用静态成员变量时
// Student s1 =new Student("张三",23,"猿究院");
// Student s2 =new Student("张三",23,"清北大学");
// System.out.println(s1); //猿究院
// System.out.println(s2); //清北大学
Student s1 =new Student("张三",23);
Student s2 =new Student("张三",23);
//可以使用对象名.变量名 不推荐
// s1.schoolName="清北";
// s2.schoolName="猿究院";
//推荐使用 类名.静态变量名--- 推荐
Student.schoolName="清华";
System.out.println(s1); //清华
System.out.println(s2); //清华
}
}
class Test1{
public static void main(String[] args) {
//测试静态方法
Student s1 =new Student("张三",23);
Student.schoolName="猿究院";
//推荐使用 类名.静态变量名--- 推荐
System.out.println("=========");
//类名.方法名
Student.eat();
System.out.println("======");
//普通方法
s1.test();
}
}
3. 接口中的常量和静态方法:
(1)常量: 因为interface
是一个特殊的“抽象类”,所以它不能定义实例成员变量。但是,interface
是可以有“静态成员变量”的,并且静态成员变量默认为final
,所以这个“静态成员变量”其实是一个常量:
public interface Person {
// 编译器会自动加上public statc final:
int MALE = 1;
int FEMALE = 2;
}实际上,因为
interface
的成员变量只能是public static final
类型,所以我们可以把这些修饰符都去掉,上述代码可以简写为:编译器会自动把该成员变量变为public static final
类型。
(2)静态方法: interface
接口中也可以有静态方法,只能使用接口名称直接调用。
interface AutoSearch{
static void quickSearch(){
//....
}
}public class Main {
public static void main(String[] args) {
// 调用接口的静态方法
AutoSearch.quickSearch();
}
}
(3)注意事项:
(3.1)接口中的默认方法,必须使用“接口实现类”的对象,才能调用。
(3.2)接口中的静态方法,必须通过“接口名.方法名()”才能进行调用。
4. static静态代码块
(1) 静态代码块的声明:在Java
类中使用static
关键字和{}
声明的静态代码块,静态代码块在“类被加载”的时候运行,而且只运行一次,并且优先于各种代码块以及构造函数。如果一个类中有多个静态代码块,会按照书写顺序依次执行。
public class CodeBlock {
static{
System.out.println("静态代码块");
}
}
(2)静态代码块的作用:
(2.1)如果有些代码逻辑或对象,需要在项目启动的时候就执行或创建,这时候就需要静态代码块。比如一个项目启动需要加载的很多配置文件或者数据库连接池对象等,我们就可以都放入静态代码块中。
(2.2)静态代码块中,只允许调用静态方法或静态的成员变量,不允许调用普通方法或普通成员变量。
class CodeBlock {
// 静态成员变量
public static int value;
static {
System.out.println("静态代码块A");
register(); // 仅允许调用静态方法
// sayHello(); // 不允许调用普通方法
// 允许使用静态成员变量(但是,需要在这个静态代码块之前先定义,再使用)
value += 10;
}
// 静态方法
public static void register(){
System.out.println("CodeBlock类的静态方法register()");
}
// 普通方法
public void sayHello() {
System.out.println("普通方法");
}
}
(3) 执行顺序:静态代码块 > 构造代码块 > 构造函数 > 普通代码块
5、总结:
(1)使用static
关键字修饰的成员变量,被称为静态成员变量,它属于所有实例“共享”的成员变量。
(2)使用static
修饰的方法,被称为静态方法。
(3)静态方法或静态成员变量,建议通过类名进行访问。(不推荐使用实例对象访问)
(4)静态方法只能可以调用静态的方法或成员变量,不能调用普通的方法或成员变量。静态方法无法访问this
。
(5)使用static
修饰的代码块,被称为静态代码块。在静态代码块在“类被加载”的时候运行,而且只运行一次。
(6)静态代码块中,只允许调用静态方法或静态的成员变量,不允许调用普通方法或普通成员变量。
(7)执行流程:静态代码块 > 构造代码块 > 构造函数 > 普通代码块。
(8)如果存在继承关系,则执行流程为:先“静态”(父类 > 子类),再“非静态”(父类 > 子类
(9)静态方法常用于工具类和辅助方法。
二、Package包:
1、定义: 在Java中,我们使用package
来解决名字冲突。Java定义了一种使用名字来命名空间的方式,称之为包:package
。一个类总是属于某个包,类名(比如Person
)只是一个简写,真正的完整类名是 包名.类名。在定义class
的时候,我们需要在第一行声明这个class
属于哪个包。
package ming; // 声明包名ming
public class Person {
}
2、包作用域:位于同一个包的类,可以访问包作用域的字段和方法。不用public
、protected
、private
修饰的字段和方法就是包作用域。例如,Person
类定义在hello
包下面:
package hello;
public class Person {
// 包作用标题三域:
void hello() {
System.out.println("Hello!");
}
}package hello;
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.hello(); // 可以调用,因为Main和Person在同一个包
}
}
3、import关键字:
在一个class
中,我们总会引用其他的class
。例如,小明的ming.Person
类,如果要引用小军的mr.jun.Arrays
类,他有三种写法:
(1)直接写出完整类名,例如:
// Person.java
package ming;public class Person {
public void run() {
mr.jun.Arrays arrays = new mr.jun.Arrays();
}
}
(2)用import
语句,导入小军的Arrays
,然后写简单类名:
// Person.java
package ming;// 导入完整类名:
import mr.jun.Arrays;public class Person {
public void run() {
Arrays arrays = new Arrays();
}
}
在写import
的时候,可以使用*
,表示把这个包下面的所有class
都导入进来(但不包括子包的class):
// Person.java
package ming;// 导入mr.jun包的所有class:
import mr.jun.*;public class Person {
public void run() {
Arrays arrays = new Arrays();
}
}
(3)使用import static
的语法,它可以导入一个类的静态字段和静态方法:
package main;
// 导入System类的所有静态字段和静态方法:
import static java.lang.System.*;public class Main {
public static void main(String[] args) {
// 相当于调用System.out.println(…)
out.println("Hello, world!");
}
}
三、作用域:
在Java中,我们经常看到public、protected、private这些修饰符。在Java中,这些修饰符可以用来限定访问作用域。
1、friendly
(默认访问修饰符): 在同一包内可见,不使用任何修饰符。使用位置:类、接口、变量、方法。
2、private
(私有访问修饰符) : 在同一类的内部可见。使用位置:变量、方法。
3、public
(公共访问修饰符): 对所有类可见。使用位置:类、接口、变量、方法
4、protected
(保护访问修饰符) : 对同一包内的类、或子类(子类可以不同包)可见。使用位置:变量、方法。
5、局部变量:在方法内部定义的变量称为局部变量,局部变量作用域从变量声明处开始到对应的块结束。方法参数也是局部变量。
package abc;
public class Hello {
void hi(String name) { // ①
String s = name.toLowerCase(); // ②
int len = s.length(); // ③
if (len < 10) { // ④
int p = 10 - len; // ⑤
for (int i=0; i<10; i++) { // ⑥
System.out.println(); // ⑦
} // ⑧
} // ⑨
} // ⑩
}● 方法参数name是局部变量,它的作用域是整个方法,即①~⑩;
● 变量s的作用域是定义处到方法结束,即②~⑩;
● 变量len的作用域是定义处到方法结束,即③~⑩;
● 变量p的作用域是定义处到if块结束,即⑤~⑨;
● 变量i的作用域是for循环,即⑥~⑧。
使用局部变量时,应该尽可能把局部变量的作用域缩小,尽可能延后声明局部变量。
6、final 修饰符:Java还提供了一个final
修饰符。final
与访问权限不冲突,它有很多作用。用final
修饰class
可以阻止被继承,修饰的变量为常量,修饰的方法不可被重写
四、内部类:
定义:有一种类,它被定义在另一个类的内部,所以称为内部类(Inner Class
)。Java
的内部类分为好几种,虽然大部分情况很少使用,但也需要了解它们语法定义及使用。
1、普通内部类:如果一个类定义在另一个类的内部,这个类就是Inner Class
:
(1)必须依赖于外部类的对象而创建,不能单独存在
(2)普通内部类可以访问外部类的所有成员变量和成员方法(包括私有的)
(3)内部类可以修改外部类的成员变量和方法
(4)内部类通过外部类名.this.成员变量(成员方法)访问成员变量(成员方法)
(5)内部类中不允许存在静态的声明变量(方法)
(6)Java
编译器编译后的.class
文件可以发现,Outer
类被编译为Outer.class
,而Inner
类被编译为Outer$Inner.class
。
class Outer {
class Inner {
// 定义了一个Inner Class
}
}
package com.yuan.outerinnerClass;
public class Outer {
private double pi = 3.114;
private static String name = "张三";
public Outer() {
System.out.println("外部类的无参构造方法");
}
static {
System.out.println("外部类的静态代码块");
}
public static void test() {
System.out.println("外部类的静态方法test");
}
@Override
public String toString() {
return "Outer{" +
"pi=" + pi +
", name='" + name + '\'' +
'}';
}
//内部类:
class inner {
private double e = 2.7;
private static final String names = "张三";
public inner() {
System.out.println("内部类的无参构造方法");
}
public void test() {
//外部类类名.this.成员变量 访问外部类成员变量
Outer.this.pi = 3.1415;
Outer.name = "李四";
//部类类名.this.方法名()
System.out.println(Outer.this.toString());
//访问外部类的静态方法
Outer.test(); //不推荐对象名用this访问
//Outer.this.test();
System.out.println(this.toString());
}
//内部类中不允许存在静态的声明
//static {
// System.out.println("这个是内部类的静态代码块");
// }
//内部类中不允许存在静态的方法
//public static void dosth(){
// System.out.println("内部类的dosth");
// }
//内部类的toString()
@Override
public String toString() {
return "inner{" +
"e=" + e +
'}';
}
}
}
class Test{
public static void main(String[] args) {
//内部类的对象必须要依赖于外部类的对象的存在而存在
//方式一、
Outer o1=new Outer();
Outer.inner i1=o1.new inner(); //创建内部类对o1的成员变量修改了
i1.test();
//方式2、
// Outer.inner i2=new Outer().new inner();
}
}
2、Anonymous Class 匿名类(重写实现):
还有一种定义Inner Class的方法,它不需要在Outer Class中明确地定义这个Class,而是在方法内部,通过匿名类(Anonymous Class)来定义。示例代码如下:
package com.yuan.outerinnerClass; public class Outer1 { private String name = "张三"; public void test() { // 匿名内部类 // 接口不能实例化对象,{} 中的内容是关于 Runnable 这个接口所写的匿名的实现类 // Runnable本身是接口,接口是不能实例化的,所以这里实际上是定义了一个实现 //了Runnable接口的匿名类,并且通过new实例化该匿名类,然后转型为Runnable。在定义匿 //名类的时候就必须实例化它,定义匿名类的写法如下: Runnable r1 = new Runnable() { @Override public void run() { System.out.println("这个是我的 run 方法" + name); } }; new Thread(r1).start(); } } class Demo02 { public static void main(String[] args) { Outer1 o1 = new Outer1(); o1.test(); // 匿名内部类 } }
3、 Static Nested Class静态内部类:
最后一种内部类和Inner Class
类似,但是使用static
修饰,称为静态内部类(Static Nested Class
):
(1)静态内部类不能访问外部类的非静态的成员变量 , 也不能出现Outer.this
(2)静态内部类不能访问外部类的非静态的成员方法
(3)静态内部类中允许存在静态代码块
(4)静态内部类中允许存在静态的方法
(5)静态内部类不依赖于外部类的对象而创建
public class Main {
public static void main(String[] args) {
Outer.StaticNested sn = new Outer.StaticNested();
sn.hello();
}
}class Outer {
private static String NAME = "OUTER";private String name;
Outer(String name) {
this.name = name;
}static class StaticNested {
void hello() {
System.out.println("Hello, " + Outer.NAME);
}
}
}