static
某些特定的数据在内存空间里只有一份,或者多个对象共用这一份数据,可以用static关键字对其进行修饰。
主要用来修饰类的结构:属性、方法、代码块、内部类
使用static修饰属性
class Chinese{
// 属性
String name;
int age;
static String nation; // 静态变量
}
public class Static {
public static void main(String[] args) {
Chinese c1 = new Chinese();
Chinese.nation = "CHN"; //可用通过“.”方法直接调用静态变量
Chinese c2 = new Chinese();
System.out.println(c2.nation); // CHN
// 静态变量的使用
c1.nation = "China";
System.out.println(c2.nation); // China
![](https://img.haomeiwen.com/i26145946/d1eb90d9496fec27.png)
- 当一个属性可以被多个对象共享,那这个属性可以被声明为static
- 静态变量:使用static修饰。如果创建类的多个对象,那么这多个对象共享一个静态变量
- 静态变量随着类的加载而加载,且类的加载早于对象创建。故静态变量与具体的对象无关,而是归为类的所有。
- 静态变量仅会加载一次,且存放在方法区中的静态域中
使用static修饰方法
class Chinese{
// 方法
public void eat(){
}
public static void show(){
// 静态方法内部只能调用静态属性和静态方法
}
}
// 静态方法的使用
Chinese.show(); // 可通过类直接进行调用
c1.show();
- 静态方法: 静态方法随着类的加载而加载,可通过类直接进行调用
- 静态方法中,只能调用静态的方法和属性
- static方法中不能使用this、super关键字(因为static方法没有明确的对象指向)
- 静态方法不能被重写
- 工具类中的方法,习惯上也声明为static(省去造对象的过程):比如Math.random()
单例设计模式(Singleton)
单例设计模式:就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
1、饿汉式
// 饿汉式
class Bank{
// 1.构造器私有化
private Bank(){
}
// 2.在类内部创建对象
// 4.静态方法只能使用静态成员
private static Bank bank = new Bank();
// 3.公共方法,以便可以使用对象
// 此方法设置为静态,以便返回同一个对象
public static Bank getInstance(){
return bank;
}
}
2、懒汉式
// 懒汉式
// 暂未修复多线程问题
class Order{
// 1.构造器私有化
private Order(){
}
// 2.在类内部创建空对象,此时不会占用存储空间
// 4.静态方法只能使用静态成员
private static Order order = null;
// 3.公共方法,以便可以使用对象,此时才会生成对象实例
// 此方法设置为静态,以便返回同一个对象
public static Order getInstance(){
if(order == null)
order = new Order();
return order;
}
}
注意:由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
代码块
// 代码块
{
内容
}
也叫做初始化块,用来对Java类或对象进行初始化
代码块只能用static进行修饰
静态代码块
静态代码块:用static 修饰的代码块
class Person{
// 属性
int age;
String name;
static String description = "default sentence...";
// 代码块
// 静态代码块
// 在加载类的时候加载
static{
System.out.println("Hello static block!");
description = "This is a static block!"; // 可修改静态属性
}
}
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
- 静态代码块的执行要先于非静态代码块。
- 静态代码块随着类的加载而加载,且只执行一次。
非静态代码块
非静态代码块:没有static修饰的代码块
class Person{
// 属性
int age;
String name;
static String description = "default sentence...";
// 非静态代码块
// 在创建对象的时候加载
{
System.out.println("Hello block!");
age = 17;
name = "Kana";
}
}
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 除了调用非静态的结构外,还可以调用静态的变量或方法。
- 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
- 每次创建对象的时候,都会执行一次。且先于构造器执行。
final
final 可用于修饰类、方法、变量
- 当final修饰类时,该类不能够被继承,比如(String类、System类、StringBuffer类)
- 当final修饰方法时,该方法不能够被重写,比如:Object类中的getClass()
- 当final修饰变量时,此变量就相当于一个常量,它可以被赋予初始值,但是不能够被修改
- final修饰属性时,可以对其进行:显示初始化、代码块中初始化、构造器中初始化
- final修饰形参时,表明此形参是一个常量。调用方法时,需要对该形参进行赋值,一旦赋值以后,就无法对其重新赋值
- static final可以组合在一起使用,可以用来修饰属性和方法
- 当用来修饰属性时,该属性相当于一个全局常量
- 当用来修饰方法时,该方法随着类的加载而加载,并且不能够被重写
抽象类与抽象方法
将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类
// 定义抽象类
abstract class AbPerson{
String name;
int age;
public AbPerson(){
}
public AbPerson(String name,int age){
this.name = name;
this.age = age;
}
public abstract void eat(); // 抽象方法
public void walk(){
System.out.println("walking...");
}
}
abstract可以修饰类和方法
当abstract修饰类:
- 该类为抽象类,不能够被实例化;
- 但仍可以有构造器,以便其子类实例化时使用。
// AbPerson p1 = new AbPerson(); // 非法
当abstract修饰方法:
- 为抽象方法,此方法不能被调用;
- 抽象方法只能存在于抽象类中;
- 只有方法的声明,没有方法体;
- 子类只有重写父类的所有抽象方法后,才可以进行实例化,否则该子类也需要被abstract修饰。
class Student extends AbPerson{
public Student(){
super();
}
public Student(String name,int age){
super(name,age);
}
// 重写抽象方法
public void eat(){
System.out.println("eating...");
}
}
补充:使用抽象类的匿名子类
public class Abstract {
public static void walk(AbPerson abPerson){
System.out.println("name:"+abPerson.name+" age:"+abPerson.age);
System.out.println("go to school!");
abPerson.eat();
}
public static void main(String[] args) {
// 补充:
// 使用匿名对象
walk(new Student("Kana",16));
// 使用抽象类的匿名子类
walk(new AbPerson("Kana",16){
public void eat(){
System.out.println("eating well");
}
});
}
}
注意点:
(抽象类理所当然地应该被子类继承,并且子类可以实例化,否则这个抽象类就没有意义)
- abstract不能修饰属性、构造器等结构
- abstract不能用来修饰私有方法(因为继承的private方法不能重写)
- abstract不能用来修饰静态方法(因为static方法由类直接加载,不能被覆盖)
- abstract不能用来修饰final的方法和类(因为final修饰的方法不能重写,final类不能被继承)
接口
java中,class与Interface是两个并列的结构;
java不支持多重继承;但有了接口,就可以得到多重继承的效果。
在jdk7中:
接口只能定义全局常量(static final)与抽象方法(abstract)。接口是抽象方法和常量值定义的集合
注:接口不能定义构造器,所以接口不能够被实例化
interface Flyable{
// 全局常量
public static final int MAX_SPEED = 7900;
int MIN_SPEED = 1; // 也可以省略关键字
// 抽象方法
public abstract void fly();
void stop(); // 也可以省略关键字
}
接口通过让类去实现的方式进行使用
class Plane implements Flyable{
@Override // 抽象方法的实现
public void fly() {
System.out.println("芜湖,起飞~");
}
@Override
public void stop() {
System.out.println("我的飞机没电了...");
}
}
若实现类覆盖了接口中所有的抽象方法,则此类可以实例化;否则,此类必须被abstract修饰
Plane p = new Plane();
p.fly();
接口的具体使用体现了多态性
比如Kite类也通过Flyable实现:
class Kite implements Flyable{
@Override // 抽象方法的实现
public void fly() {
System.out.println("飞到天上去看看!");
}
@Override
public void stop() {
System.out.println("飞累了,休息一下~");
}
}
Flyable f1 = new Plane();
Flyable f2 = new Kite();
f1.fly(); //芜湖,起飞~
f2.fly(); //飞到天上去看看!
通过接口,可以实现多继承:
// 接口之间可以多继承
interface AA{
}
interface BB{
}
interface CC extends AA,BB{
}
jdk8中对于接口的改进
jdk8中的接口,除了jdk7的特性外,还可以定义静态方法与默认方法
interface CompareA{
// 静态方法
public static void method1(){
System.out.println("111");
}
// 默认方法
public default void method2(){
System.out.println("222");
}
default void method3(){ // 可省略public
System.out.println("333");
}
}
接口中的默认方法和静态方法都可以被重写,但需要注意以下几点:
默认方法:子类可以选择性地重写接口中的默认方法,如果子类重写了默认方法,就会使用子类中的方法实现,否则就会使用接口中的默认方法实现。需要注意的是,如果一个类实现了多个接口,并且这些接口中有相同的默认方法,那么在实现类中必须重写这个方法,否则会出现编译错误。
静态方法:接口中的静态方法不能被子类重写,因为它们是在编译时期间就确定的。子类可以定义一个同名的静态方法,但它只是一个新的方法,不是重写接口中的静态方法。
需要注意的是,接口中的默认方法和静态方法都可以在实现类中被调用,但调用方式有所不同。对于默认方法,可以通过实现类的对象来调用,默认方法会使用实现类中的方法实现,如果实现类没有提供实现,就会使用接口中的默认方法实现。对于静态方法,可以通过接口名直接调用,静态方法会使用接口中的方法实现。
总之,接口中的默认方法和静态方法都可以被重写,使用时需要注意方法签名和调用方式。
class SubClass implements CompareA{
// 可对静态方法进行重写
public void method1(){
System.out.println("111-111");
}
// 可对默认方法进行重写
public void method2(){
System.out.println("222-222");
}
}
接口中的默认方法
- 若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接口时,会出现:接口冲突。
解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。
- 若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则。接口中具有相同名称和参数的默认方法会被忽略。
内部类
java中允许将一个类A声明在类B中,类A称为内部类,类B称为外部类
成员内部类
作为外部类的成员:
- 可以调用外部类的结构
- 可以被static修饰
- 可以被4种权限修饰符修饰
作为类出现:
- 具有属性、方法、构造器等...
- 可以被final修饰(不能被继承)
- 可以被abstract修饰(不能被实例化)
class Character{
String name;
public void show(){
System.out.println("Character");
}
// 静态内部类
static class BB{
String name;
public void says(){
System.out.println("BBB");
}
}
// 非静态内部类
class CC{
String name;
public void says(){
System.out.println("CCC");
}
public void showCC(){
Character.this.show(); // 调用外部类的方法
this.says();
}
}
}
// 静态内部类实例化
Character.BB bb = new Character.BB();
bb.says();
// 非静态内部类实例化
Character chara = new Character();
Character.CC cc = chara.new CC();
cc.says();
局部内部类
局部内部类可以存在于方法内、代码块内、构造器内;
class 外部类{
方法(){
class 局部内部类{...}
}
// 代码块
{
class 局部内部类{...}
}
}
如何使用局部内部类
-
只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
-
但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
class Character{
// 开发中并不常见的写法
public void method(){
// 局部内部类
class AA{
}
}
// 返回一个实现了Flyable接口的类的对象
public Flyable getFlyable(){
class Fighter implements Flyable{
// 对接口的抽象方法进行重写(内容省略)
public void fly(){ ... }
public void stop(){ ... }
}
return new Fighter();
}
}
网友评论