文章目录
一、关键字:static
1.1、static 的使用
- 一、关键字:static
- 1.1、static 的使用
- 1.2、类变量 vs 实例变量内存解析
- 1.3、static 修饰方法
- 1.4、自定义 ArrayUtil 的优化
- 1.5、static 的应用举例
- 1.6、static 的练习
- 1.7、单例(Singleton)设计模式
- 二、理解 main 方法的语法(了解)
- 三、类的成员之四:代码块
- 四、关键字:final
- 五、抽象类与抽象方法
- 5.1、抽象类应用
- 5.2、练习
- 5.3、创建抽象类的匿名子类对象
- 5.4、模板方法设计模式(TemplateMethod)
- 六、接口(interface)
- 6.1、概述
- 6.2、举例
- 6.3、接口的应用:代理模式(Proxy)
- 6.4、接口的应用:工厂模式
- 八、类的内部成员之五:内部类
- 8.1、匿名内部类
- 8.2、局部内部类的使用注意
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过 new 关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。
我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份。
例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。
/*
* static 关键字的使用
*
* 1.static:静态的。
* 2.static 可以用来修饰:属性、方法、代码块、内部类。
*
* 3.使用 static 修饰属性:静态变量(或类变量)。
* 3.1 属性:是否使用 static 修饰,又分为:静态属性 VS 非静态属性(实例变量)
* 实例变量:我们创建了类的多个对象,每个对象都独立的拥有了一套类中的非静态属性。
* 当修改其中一个非静态属性时,不会导致其他对象中同样的属性值的修饰。
* 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过静态变量去修改某一个变量时,
* 会导致其他对象调用此静态变量时,是修改过的。
* 3.2 static 修饰属性的其他说明:
* ① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用。
* ② 静态变量的加载要早于对象的创建。
* ③ 由于类只会加载一次,则静态变量在内存中也只会存在一次。存在方法区的静态域中。
*
* ④ 类变量 实例变量
* 类 yes no
* 对象 yes yes
*
* 3.3 静态属性举例:System.out.Math.PI;
*
*/
public class StaticTest {
public static void main(String[] args) {
Chinese.nation = "中国";
Chinese c1 = new Chinese();
c1.name = "姚明";
c1.age = 40;
c1.nation = "CHN";
Chinese c2 = new Chinese();
c2.name = "马龙";
c2.age = 30;
c2.nation = "CHINA";
System.out.println(c1.nation);
//编译不通过
// Chinese.name = "张继科";
}
}
//中国人
class Chinese{
String name;
int age;
static String nation;
}
1.2、类变量 vs 实例变量内存解析
/*
* 4.使用 static 修饰方法:静态方法
* ① 随着类的加载而加载,可以通过"类.静态方法"的方式调用
* ② 静态方法 非静态方法
* 类 yes no
* 对象 yes yes
* ③ 静态方法中,只能调用静态的方法或属性
* 非静态的方法中,可以调用所有的方法或属性
*
* 5.static 注意点:
* 5.1 在静态的方法内,不能使用 this 关键字、super 关键字
* 5.2 关于静态属性和静态方法的使用,大家从生命周期的角度去理解。
*
* 6.开发中,如何确定一个属性是否需要声明 static 的?
* 》 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
* 》 类中的常量也常常声明为 static
*
* 开发中,如何确定一个方法是否要声明为 static 的?
* 》 操作静态属性的方法,通常设置为 static 的
* 》 工具类中的方法,习惯上声明为 static 的。比如:Math、Arrays、Collections
*
*/
public class StaticTest {
public static void main(String[] args) {
Chinese.nation = "中国";
Chinese c1 = new Chinese();
//编译不通过
// Chinese.name = "张继科";
c1.eat();
Chinese.show();
//编译不通过
// chinese.eat();
// Chinese.info();
}
}
//中国人
class Chinese{
String name;
int age;
static String nation;
public void eat(){
System.out.println("中国人吃中餐");
//调用非静态结构
this.info();
System.out.println("name : " + name);
//调用静态结构
walk();
System.out.println("nation : " + Chinese.nation);
}
public static void show(){
System.out.println("我是一个中国人!");
// eat();
// name = "Tom";
//可以调用静态的结构
System.out.println(Chinese.nation);
walk();
}
public void info(){
System.out.println("name : " + name + ",age : " + age);
}
public static void walk(){
}
}
1.4、自定义 ArrayUtil 的优化
/*
* 自定义数组工具类
*/
public class ArrayUtil {
// 求数组的最大值
public static int getMax(int[] arr) {
int maxValue = arr[0];
for (int i = 1; i 若子类重写了父类中所有的抽象方法,此子类,
*
* abstract 使用上的注意点:
* 1.abstract 不能用来修饰变量、代码块、构造器;
*
* 2.abstract 不能用来修饰私有方法、静态方法、final 的方法、final 的类。
*
*/
public class AbstractTest {
public static void main(String[] args) {
//一旦 Person 类抽象了,就不可实例化
// Person p1 = new Person();
// p1.eat();
}
}
abstract class Creature{
public abstract void breath();
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//不是抽象方法
// public void eat(){
// System.out.println("人吃饭");
// }
//抽象方法
public abstract void eat();
public void walk(){
System.out.println("人走路");
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
}
public void eat(){
System.out.println("学生应该多吃有营养的。");
}
@Override
public void breath() {
System.out.println("学生应该呼吸新鲜的无雾霾空气");
}
}
5.1、抽象类应用
抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
问题:卡车(Truck)和驳船(RiverBarge)的燃料效率和行驶距离的计算方法完全不同。Vehicle 类不能提供计算方法,但子类可以。
/* Java 允许类设计者指定:超类声明一个方法但不提供实现,该方法的实现由子类提 供。这样的方法称为抽象方法。有一个或更多抽象方法的类称为抽象类。
* Vehicle 是一个抽象类,有两个抽象方法。
* 注意:抽象类不能实例化 new Vihicle()是非法的
*/
public abstract class Vehicle{
public abstract double calcFuelEfficiency();//计算燃料效率的抽象方法
public abstract double calcTripDistance();//计算行驶距离的抽象方法
}
public class Truck extends Vehicle{
public double calcFuelEfficiency(){
//写出计算卡车的燃料效率的具体方法
}
public double calcTripDistance(){
//写出计算卡车行驶距离的具体方法
}
}
public class RiverBarge extends Vehicle{
public double calcFuelEfficiency() {
//写出计算驳船的燃料效率的具体方法
}
public double calcTripDistance( ) {
//写出计算驳船行驶距离的具体方法
}
}
5.2、练习
/*
* 编写一个 Employee 类,声明为抽象类,
* 包含如下三个属性:name,id,salary。
* 提供必要的构造器和抽象方法:work()。
* 对于 Manager 类来说,他既是员工,还具有奖金(bonus)的属性。
* 请使用继承的思想,设计 CommonEmployee 类和 Manager 类,
* 要求类中提供必要的方法进行属性访问。
*
*/
public abstract class Employee {
private String name;
private int id;
private double salary;
public Employee(){
super();
}
public Employee(String name, int id, double salary) {
super();
this.name = name;
this.id = id;
this.salary = salary;
}
public abstract void work();
}
Manager 类
/*
* 对于 Manager 类来说,他既是员工,还具有奖金(bonus)的属性。
*
*/
public class Manager extends Employee{
private double bonus; //奖金
public Manager(double bonus) {
super();
this.bonus = bonus;
}
public Manager(String name, int id, double salary, double bonus) {
super(name, id, salary);
this.bonus = bonus;
}
@Override
public void work() {
System.out.println("管理员工,提高公司运行效率。");
}
}
CommonEmployee 类
public class CommonEmployee extends Employee {
@Override
public void work() {
System.out.println("员工在一线车间生产产品。");
}
}
测试类
/*
* 请使用继承的思想,设计 CommonEmployee 类和 Manager 类,
*/
public class EmployeeTest {
public static void main(String[] args) {
Employee manager = new Manager("库克",1001,5000,50000);
manager.work();
CommonEmployee commonEmployee = new CommonEmployee();
commonEmployee.work();
}
}
5.3、创建抽象类的匿名子类对象
public class Num {
}
abstract class Creature{
public abstract void breath();
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//不是抽象方法
// public void eat(){
// System.out.println("人吃饭");
// }
//抽象方法
public abstract void eat();
public void walk(){
System.out.println("人走路");
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
}
public Student(){
}
public void eat(){
System.out.println("学生应该多吃有营养的。");
}
@Override
public void breath() {
System.out.println("学生应该呼吸新鲜的无雾霾空气");
}
}
PersonTest 类
/*
* 抽象类的匿名子类
*
*/
public class PersonTest {
public static void main(String[] args) {
method(new Student()); //匿名对象
Worker worker = new Worker();
method1(worker); //非匿名的类非匿名的对象
method1(new Worker()); //非匿名的类匿名的对象
System.out.println("*********************");
//创建了一个匿名子类的对象:p
Person p = new Person(){
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void breath() {
System.out.println("呼吸空气");
}
};
method1(p);
System.out.println("**********************");
//创建匿名子类的匿名对象
method1(new Person(){
@Override
public void eat() {
System.out.println("吃零食");
}
@Override
public void breath() {
System.out.println("云南的空气");
}
});
}
public static void method1(Person p){
p.eat();
p.walk();
}
public static void method(Student s){
}
}
class Worker extends Person{
@Override
public void eat() {
}
@Override
public void breath() {
}
}
5.4、模板方法设计模式(TemplateMethod)
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
解决的问题:
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。 换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。
1、例 1
/*
* 抽象类的应用:模板方法的设计模式
*/
public class TemplateTest {
public static void main(String[] args) {
SubTemlate t = new SubTemlate();
t.sendTime();
}
}
abstract class Template{
//计算某段代码执行所需花费的时间
public void sendTime(){
long start = System.currentTimeMillis();
code(); //不确定部分,易变的部分
long end = System.currentTimeMillis();
System.out.println("花费的时间为:" + (end - start));
}
public abstract void code();
}
class SubTemlate extends Template{
@Override
public void code() {
for(int i = 2;i 匿名内部类只能有一个对象
* > 匿名内部类对象只能使用多态形式引用
*/
interface Product{
public double getPrice();
public String getName();
}
public class AnonymousTest{
public void test(Product p){
System.out.println("购买了一个" + p.getName() + ",花掉了" + p.getPrice());
}
public static void main(String[] args) {
AnonymousTest ta = new AnonymousTest();
//调用test方法时,需要传入一个Product参数,
//此处传入其匿名实现类的实例
ta.test(new Product(){
public double getPrice(){
return 567.8;
}
public String getName(){
return "AGP显卡";
}
});
}
}
8.2、局部内部类的使用注意
public class InnerClassTest {
// public void onCreate(){
//
// int number = 10;
//
// View.OnClickListern listener = new View.OnClickListener(){
//
// public void onClick(){
// System.out.println("hello!");
// System.out.println(number);
// }
//
// }
//
// button.setOnClickListener(listener);
//
//}
/*
* 在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话,
* 要求此局部变量声明为final的。
*
* jdk 7及之前版本:要求此局部变量显式的声明为final的
* jdk 8及之后的版本:可以省略final的声明
*
*/
public void method(){
//局部变量
int num = 10;
class AA{
public void show(){
// num = 20; //Local variable num defined in an enclosing scope must be final or effectively final
System.out.println(num);
}
}
}
}