java之七 高级类设计

static的用法

有时你希望定义一个类成员,使它的使用完全独立于该类的任何对象。通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它自己使用,而不必引用特定的实例。在成员的声明前面加上关键字static(静态的)就能创建这样的成员。

如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。你可以将方法和变量都声明为static。static成员的最常见的例子是main( )。因为在程序开始执行时必须调用main(),所以它被声明为static。

声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。

声明为static的方法有以下几条限制:

· 它们仅能调用其他的static方法。

· 它们只能访问static数据。

· 它们不能以任何方式引用this或super(关键字super与继承有关,在下一章中描述)。

如果你需要通过计算来初始化你的static变量,你可以声明一个static块,static块仅在该类被加载时执行一次。 下面的例子显示的类有一个static方法, 一些static变量, 以及一个static初始化块:

// Demonstrate static variables,methods,and blocks.

class UseStatic {

static inta = 3;

static intb;

static voidmeth(int x) {

System.out.println("x = " + x);

System.out.println("a = " + a);

System.out.println("b = " + b);

}

static {

System.out.println("Static block initialized.");

b = a * 4;

}

publicstatic void main(String args[]) {

meth(42);

}

}

一旦UseStatic类被装载,所有的static语句被运行。首先,a被设置为3,接着static块执行(打印一条消息),最后,b被初始化为a*4或12。然后调用main(),main()调用meth(),把值42传递给x。3个println ( )语句引用两个static变量a和b,以及局部变量x 。

注意:在一个static方法中引用任何实例变量都是非法的。

下面是该程序的输出:

Static block initialized.

x = 42

a = 3

b = 12

在定义它们的类的外面,static方法和变量能独立于任何对象而被使用。这样,你只要在类的名字后面加点号运算符即可。例如,如果你希望从类外面调用一个static方法,你可以使用下面通用的格式:

classname.method( )

这里,classname  是类的名字,在该类中定义static方法。可以看到,这种格式与通过对象引用变量调用非static方法的格式类似。一个static变量可以以同样的格式来访问——类名加点号运算符。这就是Java如何实现全局功能和全局变量的一个控制版本。

下面是一个例子。在main()中,static方法callme()和static变量b在它们的类之外被访问。

class StaticDemo {

static inta = 42;

static intb = 99;

static voidcallme() {

System.out.println("a = " + a);

}

}

class StaticByName {

publicstatic void main(String args[]) {

StaticDemo.callme();

System.out.println("b = " +StaticDemo.b);

}

}

下面是该程序的输出:

a = 42

b = 99

使用final关键字

一个变量可以声明为final, 这样做的目的是阻止它的内容被修改。这意味着在声明final变量的时候,你必须初始化它(在这种用法上,final类似于C/C++中的const)。例如:

final int FILE_NEW = 1;

final int FILE_OPEN = 2;

final int FILE_SAVE = 3;

final int FILE_SAVEAS = 4;

final int FILE_QUIT = 5;

你的程序的随后部分现在可以使用 FILE_OPEN等等,就好像它们是常数,不必担心它们的值会被改变。

为final变量的所有的字符选择大写是一个普遍的编码约定。声明为final的变量在实例中不占用内存。这样,一个final变量实质上是一个常数。

关键字final也可以被应用于方法,但是它的意思和它被用于变量实质上是不同的。final的第二种用法将在下一章描述继承时解释。

java枚举

Enum作为Sun全新引进的一个关键字,看起来很象是特殊的class, 它也可以有自己的变量,可以定义自己的方法,可以实现一个或者多个接口。当我们在声明一个enum类型时,我们应该注意到enum类型有如下的一些特征。

1.它不能有public的构造函数,这样做可以保证客户代码没有办法新建一个enum的实例。

2.所有枚举值都是public , static , final的。注意这一点只是针对于枚举值,我们可以和在普通类里面定义变量一样定义其它任何类型的非枚举变量,这些变量可以用任何你想用的修饰符。

3.Enum默认实现了java.lang.Comparable接口。

4.Enum覆载了了toString方法,因此我们如果调用Color.Blue.toString()默认返回字符串”Blue”.

5.Enum提供了一个valueOf方法,这个方法和toString方法是相对应的。调用valueOf(“Blue”)将返回Color.Blue.因此我们在自己重写toString方法的时候就要注意到这一点,一把来说应该相对应地重写valueOf方法。

6.Enum还提供了values方法,这个方法使你能够方便的遍历所有的枚举值。

7.Enum还有一个oridinal的方法,这个方法返回枚举值在枚举类种的顺序,这个顺序根据枚举值声明的顺序而定,这里Color.Red.ordinal()返回0。

1.遍历所有有枚举值. 知道了有values方法,我们可以轻车熟路地用ForEach循环来遍历了枚举值了。

for (Color c: Color.values())

System.out.println(“find value:” + c);

2.在enum中定义方法和变量,比如我们可以为Color增加一个方法随机返回一个颜色。

public enum Color ...{

Red,

Green,

Blue;

/**//*

*定义一个变量表示枚举值的数目。

*(我有点奇怪为什么sun没有给enum直接提供一个size方法).

*/

private static int number = Color.values().length ;

/** *//**

* 随机返回一个枚举值

@return a random enum value.

*/

public static Color getRandomColor()...{

long random = System.currentTimeMillis() % number;

switch ((int) random)...{

case 0:

return Color.Red;

case 1:

return Color.Green;

case 2:

return Color.Blue;

default : return Color.Red;

}

}

}

可以看出这在枚举类型里定义变量和方法和在普通类里面定义方法和变量没有什么区别。唯一要注意的只是变量和方法定义必须放在所有枚举值定义的后面,否则编译器会给出一个错误。

3.覆载(Override)toString, valueOf方法。

前面我们已经知道enum提供了toString,valueOf等方法,很多时候我们都需要覆载默认的toString方法,那么对于enum我们怎么做呢。其实这和覆载一个普通class的toString方法没有什么区别。

….

public String toString()...{

switch (this)...{

case Red:

return "Color.Red";

case Green:

return "Color.Green";

case Blue:

return "Color.Blue";

default:

return "Unknow Color";

}

}….

这时我们可以看到,此时再用前面的遍历代码打印出来的是

Color.Red

Color.Green

Color.Blue

而不是

Red

Green

Blue.

可以看到toString确实是被覆载了。一般来说在覆载toString的时候我们同时也应该覆载valueOf方法,以保持它们相互的一致性。

4.使用构造函数。

虽然enum不可以有public的构造函数,但是我们还是可以定义private的构造函数,在enum内部使用。还是用Color这个例子。

public enum Color ...{

Red("This is Red"),

Green("This is Green"),

Blue("This is Blue");

private String desc;

Color(String desc)...{

this.desc = desc;

}

public String getDesc()...{

return this.desc;

}

}

这里我们为每一个颜色提供了一个说明信息

public enum Color ...{

Red ...{

public String toString()...{

return "Color.Red";

}

},

Green ...{

public String toString()...{

return "Color.Green";

}

},

Blue...{

public String toString()...{

return "Color.Blue";

}

};

}

, 然后定义了一个构造函数接受这个说明信息。

要注意这里构造函数不能为public或者protected, 从而保证构造函数只能在内部使用,客户代码不能new一个枚举值的实例出来。这也是完全符合情理的,因为我们知道枚举值是publicstatic final的常量而已。

5.实现特定的接口

我们已经知道enum可以定义变量和方法,它要实现一个接口也和普通class实现一个接口一样,这里就不作示例了。

6.定义枚举值自己的方法。

前面我们看到可以为enum定义一些方法,其实我们甚至可以为每一个枚举值定义方法。这样,我们前面覆载 toString的例子可以被改写成这样。

从逻辑上来说这样比原先提供一个“全局“的toString方法要清晰一些。

总的来说,enum作为一个全新定义的类型,是希望能够帮助程序员写出的代码更加简单易懂,个人觉得一般也不需要过多的使用enum的一些高级特性,否则就和简单易懂的初衷想违背了。

Java静态导入

从jdk5.0开始,import不仅可以导入类,还可以导入静态方法和静态域。

如果在源文件顶部添加import static java.lang.System.*;

那么就可以使用System类的静态方法和静态域,而不必加类前缀如:

out.println("hello world"); 相当于 System.out.println("helloworld");

exit(0); 相当于 System.exit(0);

静态方法导入和导入静态域有两个实际的应用:

1.算术函数,对Math类使用静态导入,就能更自然的使用算术函数

sqrt(pow(x,2)+pow(y,2));

2.笨重的常量,如果需要使用大量带有冗长名字的常量,就应该使用静态导入

Date d = new Date();

if(d.get(DAY_OF_WEEK) == MONDAY)

看起来比

if(d.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY)

清晰

代码:

import static java.lang.Math.pow;

import static java.lang.Math.sqrt;

import static java.lang.System.out;

import static java.util.Calendar.MONDAY;

import java.util.Date;

public class StaticImportTest {

/**

* @param args

*/

public static void main(String[] args) {

out.println("hello");

int x = 5,y=10;

double d = sqrt(pow(x,2) + pow(y,2));

out.println(d);

Date date = new Date();

if(date.getDay() == MONDAY)

out.println("今天星期1");

else{

out.println("今天星期"+ date.getDay());

}

}

}

使用final关键字

Java语言中答应有一种叫做抽象方法的东西,他只是一个名字没有具体的实现。像是这样: public abstract void abc();使用了abstract要害字,结尾用“;”结束。与前几节我们用的方法都是具体方法,是有实现的。哪怕方法体中什么也不写public void abc() { } 也是具体方法。

概念:包含一个或多个抽象方法的类称为抽象类。抽象类也必须声明abstract要害字。抽象类的使用有着一些限制,不能创建抽象类的实例。假如子类实现了抽象方法,则可以创建该子类的实例对象。要是子类也不实现的话,这个子类也是抽象类,也不能创建实例。

接口是什么东西呢?接口是比抽象类更抽象的类。举例: public interface Name { }接口里面的方法全都是抽象的,里面的变量全都是final的常量,而且实现接口的类必须将所有的抽象方法全部实现。抽象类里也可以有具体的方法。所以说,接口是最抽象的,其次是抽象类,而具体类本身就是对现实世界的抽象。软件开发本身就是将现实世界抽象成计算机世界。

因为抽象类和接口比具体类抽象,所以使用时他们总是被继续而被实现的。不过继续他们的类不只是一个,有很多类实现他们的抽象方法。一个方法有多种实现方式,这里用到了OOP中的多态性。这使得设计变得非常清楚。因为基类是抽象类或是接口做一个描述,底下继续的类有若干个,我们只需要对接口或抽象类操作,也用不着管有多少个实现。假如是多人共同开发的项目的话,是非常有意义的。你自己写个东西,怎么实现的也不用告诉别人,别人看个接口就够了。

接口的实现用要害字implement 而不是extends.假如用了extends的那就是继续这个接口。那么那个子类也是接口,是原来的子接口。举个接口的例子吧:

实践:


//声明一个接口

public interface Say {

public void sayMessage();

}

//两个实现类

public class SayHello implements Say {

public void sayMessage() {

System.out.println("hello");

}}

public class SayHi implements Say {

public void sayMessage() {

System.out.println("Hi");

}}

//这是一个测试类

public class TestSay {

public static void main(String[] args) {

//同样都是用Say这个接口类型实例,却可以输出两个结果

Say say = new SayHello();

say.sayMessage();

Say say1 = new SayHi();

say1.sayMessage();

}}

接口还有一个重要的作用,我们在面向对象那节课里提过一个概念,java语言中只有单继续,就是说只能从一个父类继续。单继续的好处是,一旦继续的太多了,改了一个类子类就都变了。牵一发,而动全身。那么假如我们想继续多个父类的特性怎么办呢?就用接口吧,这个类可以先继续一个类,再去实现其它的接口,接口里面都是抽象方法,不会造成,牵一发,而动全身的效应。改变多继续的特性,也是对C++语言的一项改进。

业界有一种说法说,与其说java是面向对象编程,还不如说它是面向接口编程。强调的方面是接口的抽象描述性。它也是对C++的一种改进,C++里面没有接口。所以说java语言适合多人团队合作的大项目,看一个接口就可以了,后面怎么实现的可以不管。

实践问题:

1.      现实世界中,公共物品是不是放在大家都能看到或找到的地方;与我们学的关键字static有什么相似和区别?

2.      生活中有些事情是固定不变的,比如法律制度是很多年不变的;这些和我们学的关键字final有什么相似和区别的地方?

3.      如果要建一座大楼,首先要设计图纸;然后把主题的框架搭建好;然后再具体的做进一步的细致工作;最后,一座大楼就建成了;这些步骤与我们软件工程之前存在什么关系;哪个步骤类似于软件中的设计抽象类和接口的过程?

小结:

在本章中,我们主要学习了:

u      关键字static、final及相关应用;

u      Java枚举类型;

u      Java静态导入

u      抽象类和接口的使用

英语词汇:

 

英文                    全文                           中文

 

Static     Static            静态的

Final         Final             终结

Enum          Enum              枚举

Import                  Import                         导入

练习项目:

总结人类使用火的手段及火的器具;比如灭火器(经常固定位置的)、打火机(经常使用的)、原始人使用的火种(经典神圣的)等;可以对人对火的形容词汇做个总结归结到枚举类型中;例如:风风火火、火急火燎等;并对人类的进化做继承归纳;用面向对象及本章缩写的知识写出相关代码;

时间: 2024-08-02 20:45:01

java之七 高级类设计的相关文章

Java基础-继承-编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight。小车类Car是Vehicle的子类,其中包含的属性有载人数 loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。每个 类都有构造方法和输出相关数据的方法。最后,写一个测试类来测试这些类的功 能。

#29.编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight.小车类Car是Vehicle的子类,其中包含的属性有载人数 loader.卡车类Truck是Car类的子类,其中包含的属性有载重量payload.每个 类都有构造方法和输出相关数据的方法.最后,写一个测试类来测试这些类的功 能. package hanqi; public class Vehicle { private int wheels; private int weight

Java之六 类设计

多态 普通的方法重载 在Java中,同一个类中的2个或2个以上的方法可以有同一个名字,只要它们的参数声明不同即可.在这种情况下,该方法就被称为重载(overloaded),这个过程称为方法重载(method overloading).方法重载是Java实现多态性的一种方式.如果你以前从来没有使用过一种允许方法重载的语言,这个概念最初可能有点奇怪.但是你将看到,方法重载是Java最激动人心和最有用的特性之一. 当一个重载方法被调用时,Java用参数的类型和(或)数量来表明实际调用的重载方法的版本.

[Java聊天室服务器]实战之七 客户端类

前言 学习任何一个稍有难度的技术,要对其有充分理性的分析,之后果断做出决定---->也就是人们常说的"多谋善断":本系列虽然涉及的是socket相关的知识,但学习之前,更想和广大程序员分享的是一种心境:学习是一个循序渐进的过程,心态应该随时调节,保持戒骄戒躁的状态.比如最近在看网易公开课MIT<算法导论>,老师提到,学习算法之前要计算机数学+离散数学+概率论等课程的知识,所以一直学不好算法的程序员不妨从基础入手,这都是中国式教育惹的祸啊!(此处省略一万字......)

在java中String类为什么要设计成final?

大神链接:在java中String类为什么要设计成final? - 程序员 - 知乎 我进行了重新排版,并且更换了其中的一个例子,让我们更好理解. String很多实用的特性,比如说"不可变性",是工程师精心设计的艺术品!艺术品易碎!用final就是拒绝继承,防止世界被熊孩子破坏,维护世界和平! 1. 什么是不可变? String不可变很简单,如下图,给一个已有字符串"abcd"第二次赋值成"abcedl",不是在原内存地址上修改数据,而是重新指

java里String类为何被设计为final

前些天面试遇到一个非常难的关于String的问题,"String为何被设计为不可变的"?类似的问题也有"String为何被设计为final?"个人认为还是前面一种问法更准确,设计成final仅仅保证了String类不能被继承,而Immutable相对于final要严格的多. 下文主要翻译自:http://java67.blogspot.sg/2014/01/why-string-class-has-made-immutable-or-final-java.html

Java编程思想之七复用类

复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须做更多的事情. 使用类而不破坏程序代码: 在新类中产生现有对象.由于新的类是由现有类的对象组成,所有这种方法称为组合. 按照现有类的类型来创建新类.无需改变现有类的形式,采用现有类的形式并在其中添加新代码.这种方法是继承. 7.1 组合语法 组合只需要将对象引用置于新类中就可以了. 但编译器并不是简单的为每一个引用都创建默认对象.如果想初始化这些引用,可以在代码中下列位置进行:

深入理解Java虚拟机(类文件结构)

深入理解Java虚拟机(类文件结构) 欢迎关注微信公众号:BaronTalk,获取更多精彩好文! 之前在阅读 ASM 文档时,对于已编译类的结构.方法描述符.访问标志.ACC_PUBLIC.ACC_PRIVATE.各种字节码指令等等许多概念听起来都是云山雾罩.一知半解,原因就在于对类文件结构和类加载机制不够了解.直到后来细读了<深入理解 Java 虚拟机>中虚拟机执行子系统的相关内容,才建立了清晰的认知.如果你也和我一样,不了解类结构和类加载,但是工作中又涉及到字节码相关内容,相信后面两篇文章

【总结】Effective java经验之谈,类与接口

转载请注明出处:http://blog.csdn.NET/supera_li/article/details/44940563 Effective Java系列 1.Effective java经验之谈,创建和销毁对象 2.Effective java经验之谈,泛型 3.Effective java经验之谈,类与接口 4.Effective java经验之谈,通用方法 5.Effective java经验之谈,枚举,注解,方法,通用设计,异常 6.Effective java经验之谈,并发编程

java之常用类的用法

知识点: 包装类基本知识 JAVA并不是纯面向对象的语言.Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的. 但是我们在实际使用中经常需要将基本数据转化成对象,便于操作.比如:集合的操作中. 例如使用Map对象要操作put()方法时,需要传入的参数是对象而不是基本数据类型. 为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class). 1)定义:将基本类型封装成类,其中包含属性和