5,static关键字
static是一个特殊的关键字,static的作用是将实例成员变为类成员,只能修饰在类里定义的成员部分(成员变量、方法、内部类(枚举和接口)、初始化块)。static修饰的成员表明它属于这个类本身,而不属于该类的单个实例,因为通常把static修饰的成员变量和方法也称为:类变量、类方法。
5.1,static声明属性
static:使用static声明的属性,此属性为全局属性(静态属性),static声明的属性是所有对象共享的。
class Person{ static String name; private int age; public Person(String name,int age) { this.setName(name); this.age = age; } public void setName(String name) { this.name = name; } public String getMessage(){ return "姓名:"+name+" 年龄:"+age; } } public class HelloWord { public static void main(String[] args) { Person person = new Person("燕双嘤",30); Person person2 = new Person("杜马",40); System.out.println(person.getMessage()+" "+person2.getMessage()); person.setName("步鹰"); System.out.println(person.getMessage()+" "+person2.getMessage()); } } ========================================================================== 姓名:杜马 年龄:30 姓名:杜马 年龄:40 姓名:步鹰 年龄:30 姓名:步鹰 年龄:40
Java中常用的内存区域:
- 栈内存空间:保存所有的对象名称(更准确来说是保存了引用的堆内存空间的地址)
- 堆内存空间:保存每个对象的具体属性内容
- 全局数据区:保存static类型的属性
- 全局代码区:保存所有的方法定义
5.2,static声明方法
static声明的方法,被称为“类方法”,可以由类名直接调用。Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
class Person{ private static String name; private int age; public Person(String name,int age) { this.setName(name); this.age = age; } public static void setName(String n) { name = n; } public String getMessage(){ return "姓名:"+name+" 年龄:"+age; } } public class HelloWord { public static void main(String[] args) { Person person = new Person("燕双嘤",30); Person person2 = new Person("杜马",40); System.out.println(person.getMessage()+" "+person2.getMessage()); Person.setName("步鹰"); System.out.println(person.getMessage()+" "+person2.getMessage()); } } ========================================================================== 姓名:杜马 年龄:30 姓名:杜马 年龄:40 姓名:步鹰 年龄:30 姓名:步鹰 年龄:40
Person类将所有的属性都进行了封装,所以要想设置属性就必须使用setter()方法,但是这里的方法是使用static声明的,所以可以直接用类名调用。
另外:非static声明的方法可以去调用static声明的属性或方法。但是static声明的方法是不能调用非static类型声明的属性或方法的。
原因:在程序中所有的属性和方法必须在对象开辟堆内存之后才可以调用,而static类型的方法在对象未被实例化时就可以被类名调用(不在堆栈内存,而在全局数据区内存),所以如果直接由static方法调用非static操作,则有可能在属性还没被初始化时(没放入堆栈内存)就被调用。这也就解释了为啥main方法中调用本类的其他方法只能调用静态方法。
5.3,理解main方法
还记得HelloWord吗?
public class HelloWord { public static void main(String[] args) { System.out.println("HelloWord"); } }
public 表示此方法可以被外部调用 static 表示此方法可以由类名称直接调用 void 主方法是程序的起点,所以不需要任何的返回值 main 系统规定好默认调用的方法名称,执行时默认找到main方法名称 String args[] 表示的是运行时的参数。参数传递的形式:Java类名称,参数1,参数2,参数3...
6,代码块
6.1,普通代码块
定义变量时指定的初始值和代码块中指定的初始值的执行顺序与它们在源程序的排列顺序相同。
public static void main(String[] args) { { int x = 30; System.out.println(x); } int x = 40; System.out.println(x); } =============================== 30 40
public static void main(String[] args) { int x = 40; System.out.println(x); { x = 30; System.out.println(x); } } =========================== 40 30
6.2,构造块
构造代码块是直接写在类中的代码块。构造块优先于构造方法执行,而且每次实例化对象都会执行构造块中的代码,会执行多次。
class Person{ { System.out.println("Hello"); } public Person(){ System.out.println("Word"); } } public class HelloWord { public static void main(String[] args) { new Person(); } } ============================================ Hello Word
6.3,静态代码块
class Person { { System.out.println("父类非静态代码块"); } static { System.out.println("父类静态代码块"); } public Person() { System.out.println("父类构造方法"); } } public class Child extends Person { { System.out.println("子类非静态代码块"); } public Child() { System.out.println("子类构造方法"); } static { System.out.println("子类静态代码块"); } public static void main(String[] args) { new Child(); new Child(); } } =========================== 父类静态代码块 子类静态代码块 父类非静态代码块 父类构造方法 子类非静态代码块 子类构造方法 父类非静态代码块 父类构造方法 子类非静态代码块 子类构造方法
静态代码块优先于主方法执行,而在类中定义的静态代码快会优先于构造方法执行,不管有多个个对象产生,静态代码块只执行一次。
7,构造方法私有化
7.1,问题的提出
类的封装性不只体现在对属性的封装上,实际上方法也是可以被封装的。
class Person{ private Person(){ System.out.println("构造方法"); } } public class HelloWord { public static void main(String[] args) { new Person(); } }
这样就会报错:'Person()' has private access in 'Package2.Person'
解决办法:在内部产生本类的实例化对象
7.2,问题的解决
class Person{ static Person instance = new Person(); private Person(){ System.out.println("构造方法"); } public void print(){ System.out.println("你好"); } } public class HelloWord { public static void main(String[] args) { Person person = Person.instance; person.print(); } } ============================================ 构造方法 你好
程序成功取得了instance的实例化对象并调用了其中的print()方法。但是这样做会存在问题(因为类中的属性必须封装),所以此处应该将instance属性进行封装,而封装之后必须通过方法取得,但以因为instance属性属于静态属性,所以此处必须声明一个静态方法,这样就可以被类名直接调用。
class Person{ static Person instance = new Person(); public static Person getInstance() { return instance; } public static void setInstance(Person instance) { Person.instance = instance; } private Person(){ System.out.println("构造方法"); } public void print(){ System.out.println("你好"); } } public class HelloWord { public static void main(String[] args) { Person person1 = Person.getInstance(); Person person2 = Person.getInstance(); Person person3 = Person.getInstance(); person1.print();person2.print();person3.print(); } } ================================= 构造方法 你好 构造方法 你好 构造方法 你好
7.3,程序的意义
上面的程序中可以发现虽然声明了3个Person对象,但是实际上所有的对象都只使用一个instance引用,也就是说,此时不管外面如何使用,最终结果程序中也只有一个Person类的实例化对象存在。
这就是是设计模式中的单例设计模式:无论程序怎样运行,Person永远只有一个实例化对象存在,就可以控制实例化对象的产生。
8,内部类
8.1,内部类的基本定义
在内部类可定义成员变量与方法,而且在类内部也可以定义另一个类。Java从JDK1.1开始引入内部类,内部类主要作用如下:
- 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包下的其他类访问该类。
- 内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问。
- 匿名内部类适合于创建那些仅需要一次使用的类。
- 采用内部类这种技术,可以隐藏细节和内部结构,封装性更好,让程序的结构更加合理!如果类很多且都暴露在外面,那么类与类之间的调用就会十分繁琐!
内部类与外部类的区别:
- 内部类比外部类可以多使用三个修饰符:private、protected、static——外部类不能使用。
- 非静态内部类不能拥有静态成员。
class Outer{ private String info = "hello world!!!"; class Inner{ public void print(){ System.out.println(info); } }; public void fun(){ new Inner().print(); } } public class HelloWord { public static void main(String[] args) { new Outer().fun(); } } ============================================ hello world!!!
Inner类作为Outer类的内部类存在,并且在外部类的fun()方法之中直接实例化内部类的对象并调用方法print(),但是从以上代码中可以明显地发现,内部类的存在实际上已经破坏了一个类的基本结构,因为类是由属性及方法组成的,所以这是内部类的一个缺点。
解决方法如下:
class Outer{ private String info = "hello world!!!"; public String getInfo(){ return this.info; } public void fun(){ new Inner(this).print(); } } class Inner{ private Outer out = null; public Inner(Outer out){ this.out = out; } public void print(){ System.out.println(out.getInfo()); } } public class HelloWord { public static void main(String[] args) { new Outer().fun(); } }
8.2,成员内部类(非静态内部类)
成员内部类(非静态内部类)的使用就是将内部类作为外部类的的一个成员变量/成员方法来使用,所以必须依赖于外部类的对象才能调用,用法和成员变量/成员方法一致!
class Outer{ private static String info = "hello world!!!"; class Inner{ public void print(){ System.out.println(info); } } } public class HelloWord { public static void main(String[] args) { Outer out = new Outer(); Outer.Inner in = out.new Inner(); in.print(); } }
8.3,使用static定义内部类(静态内部类)
使用static可以声明属性或方法,而使用static也可以声明内部类,用static声明的内部类变成了外部类,但是用static声明的内部类不能访问非static的外部类属性。如果将info去掉static,则编译时将出现错误。
class Outer{ private static String info = "hello world!!!"; static class Inner{ public void print(){ System.out.println(info); } } } public class HelloWord { public static void main(String[] args) { new Outer.Inner().print(); } }
8.4,在方法中定义内部类(局部内部类)
可以在方法中定义一个内部类,但是在方法中定义的内部类不能直接访问方法中的参数,如果方法中的参数想要被内部类所访问,必须加上final关键字。
class Outer{ private String info = "hello world!!!"; public void fun(final int temp){ class Inner{ public void print(){ System.out.println("类中的属性:"+info); System.out.println("方法中的参数:"+temp); } }; new Inner().print(); } }; public class HelloWord { public static void main(String[] args) { new Outer().fun(30); } }