第四章、Java面向对象(七)
本人也是刚入门Java语言,可能会有一些地方出现错误,描述的不对。如果发现不对的地方请及时指出,好对其进行修改。这样不仅可以让我学到东西,也可以让其他刚入门的朋友学习更正确的内容。
所有内容仅供参考。不具有完全的准确性!
注:关于Java的所有内容都会参考到尚硅谷在网上公开的学习视频及其提供的PPT
一、static关键字的使用
推荐:https://www.cnblogs.com/dolphin0520/p/3799052.html
(一)为什么要使用static
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。
(二)static的作用
static : adj.静态的
-
在《Java编程思想》P86页有这样一段话:
“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。” -
修饰类的属性和方法
- 类属性作为该类各个对象之间共享的变量。在设计类时,分析哪些属性不因对象的不同而改变,将这些属性设置为类属性。相应的方法设置为类方法。
- 如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。
-
使用范围:
在Java类中,可用static修饰属性、方法、代码块、内部类 -
被修饰后的成员具备以下特点:
- 随着类的加载而加载
- 优先于对象存在
- 修饰的成员,被所有对象所共享
- 访问权限允许时,可不创建对象,直接被类调用
(三)static修饰属性
格式:
修饰符 static 属性类型 属性名 = 初始化值;
例:
public static String CN = "中国";
static修饰成员变量也称作静态成员变量(静态属性),静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。
注意:如果有一个对象对static修饰的属性修改了其属性值,则其他所有的对象再使用该属性时,得到的都是被修改过的值。
(四)static修饰方法
没有对象的实例时,可以用类名.方法名()的形式访问由static修饰的类方法。
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。
例:
String name;
static String nation;
public void eat(){
sleep();//合法
name = "张三"; //合法
nation = "CN"; //合法
}
public static void walk(){
}
public static void sleep(){
eat();//非法
name = "李四"; // 非法
nation = "CN"; //合法
walk(); //合法
}
注意:static修饰的方法不能被重写
(五)static的误区
1、 static关键字会改变类中成员的访问权限吗?
Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)
2、能通过this访问静态成员变量吗?
可以。静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)
3、static能作用于局部变量么?
Java中static是不允许用来修饰局部变量
(六)静态类
通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。
(七)static和final同时使用表示什么
static final用来修饰成员变量和成员方法,可简单理解为“全局常量”!对于变量,表示一旦给值就不可修改,并且通过类名可以访问。对于方法,表示不可覆盖,并且可以通过类名直接访问。
参考资料:https://www.cnblogs.com/dulixiaoqiao/p/6642410.html
二、代码块
- 代码块(或初始化块)的作用:
对Java类或对象进行初始化 - 代码块(或初始化块)的分类:
一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块(static block),没有使用static修饰的,为非静态代码块。 - static代码块通常用于初始化static的属性
class Person {
public static int total;
static {
total = 100;//为total赋初值
}
…… //其它属性或方法声明
}
静态代码块:用static 修饰的代码块
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
- 静态代码块的执行要先于非静态代码块。
- 静态代码块随着类的加载而加载,且只执行一次。
非静态代码块:没有static修饰的代码块
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 除了调用非静态的结构外,还可以调用静态的变量或方法。
- 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
- 每次创建对象的时候,都会执行一次。且先于构造器执行。
三、final关键字
final : adj.最终的
final可以用来修饰的结构:类、方法、变量final 用来修饰一个类:此类不能被其他类所继承。
比如:String类、System类、StringBuffer类
public final class String
- final标记的类不能被继承。提高安全性,提高程序的可读性。
String类、System类、StringBuffer类 - final标记的方法不能被子类重写。
比如:Object类中的getClass()。 - final标记的变量(成员变量或局部变量)即称为常量。名称通常全部大写,且只能被赋值一次。
- final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
- final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
注意:final标记的成员变量必须在声明时或在每个构造器中或代码块中显式赋值,然后才能使用。
static final:全局常量
四、抽象类和抽象方法
相关的关键字:abstract: adj.抽象的
(一)为什么要有抽象
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
(二)什么是抽象类和方法
- 用abstract关键字来修饰一个类,这个类叫做抽象类。
① 此类不能实例化
② 抽象类中一定有构造器,便于子类实例化时调用
③ 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作 - 用abstract来修饰一个方法,该方法叫做抽象方法。
① 只有方法的声明,没有方法体
② 包含抽象方法的类一定是抽象类,反之,抽象类中可以没有抽象方法
③ 若子类重写了父类中所有的抽象方法后,此子类才可以实例化
④ 若没有重写父类中所有的抽象方法,则此方法也是一个抽象类,需要使用abstract修饰
抽象方法:只有方法的声明,没有方法的实现。以分号结束:
比如:public abstract void talk(); - 含有抽象方法的类必须被声明为抽象类。
- 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类,其子类继承后仍需要重写没有被重写的抽象方法。
注意:
- 不能用abstract修饰变量、代码块、构造器;
- 不能用abstract修饰私有方法、静态方法、final的方法、final的类。
(三)抽象类的使用
抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
比如:计算每种几个图形的方法都有差异,此时就可以声明一个计算面积的抽象方法,然后每种图形的类分别继承该抽象类,然后将自己具体的计算方式写在重写该方法后的方法体中。
例:
abstract class Graphical{
public abstract double area();
}
//圆形
class Circular extends Graphical{
@Override
public double area() {
int r = 10;
return 3.14 * r * r;
}
}
//矩形
class Rectangle extends Graphical{
@Override
public double area() {
int a = 10;
int b = 10;
return a * b;
}
}