classUserInfo{
public static voidmain(Stringargs[])
{
{
int a = 0;
}
}
}
2)变量的初始化:
Java中的变量初始化规则是这样的:类变量和实例变量在没有进行显示初始化的时候,系统会自动赋予默认值,这里需要补充的是所有继承于Object的默认值为null,块变量和局部变量必须进行显示赋值操作,否则无法通过编译器的编译。这一点用下边的代码段来说明:
class UserInfo{
int a;
public static void main(String args[])
{
int b;
System.out.println(b);//这句话无法通过编译器的编译,因为是局部变量,没有进行显示初始化操作
System.out.println(a); //这句话的输出为0,因为系统自动初始化了一个默认值
}
}
Java中有一种初始化的方式称为静态初始化,静态初始化会存在于class域的一个static块语句里面,所有静态初始化的语句会在类加载的时候第一时间执行,所以看下边这句代码:
class UserInfo{
static int a = 0;
static{
System.out.println("Init static");
}
public static void main(String args[])
{
System.out.println("Init main");
}
}
上边代码运行一次可以知道,静态初始化块是最先执行的,输出会如下:
Init static
Init main
这种静态初始化的方式在我们使用JDBC的时候我们会经常用来进行驱动的加载,而且它还有一个特性是:它只运行一次!其含义在于,及时以后使用该类去创建实例,这一段再也不会执行,因为静态初始化属于Class域的操作,仅仅在类第一次被JVM加载的时候会执行,以后就不会再执行了。
3)Java变量修饰符和访问域(变量相关):
在面向对象里面,我们设计的时候需要实现信息隐藏,同理而言,就是我们在设计类的属性和对应的成员函数的时候需要使用变量和函数的修饰符来操作,在Java语言里面,总共分为四种访问域:
public域:public域使用public关键字来实现,该域里面的内容是任何成员都可以访问的,访问前提是已经导入了该类所在的包
protected域:protected域使用protected关键字来实现,该域里面的内容访问限制在于:访问该类的类必须和被访问类在同一个包里面,或者访问类是被访问类的子类,这两种关系满足protected域的访问规则
default域:default域不需要用任何关键字来实现,直接在类里面定义实例变量或者类变量的时候不带任何修饰符,该域的访问规则是:访问类和被访问类必须在同一个包里,因为这个原因,default域又可以称为包域
private域:private域使用private关键字实现,访问规则为:该关键字定义的东西只有该类本身可以访问,其他类以及子类都不可以访问该成员
按照以下的表可以知道这几个修饰符之间的大小和相互之间的访问关系
|
所有成员 |
子类成员 |
同一个包 |
本类成员 |
public |
可访问 |
可访问 |
可访问 |
可访问 |
protected |
不可访问 |
可访问 |
可访问 |
可访问 |
default |
不可访问 |
不可访问* |
可访问 |
可访问 |
private |
不可访问 |
不可访问 |
不可访问 |
可访问 |
*注意:这里需要注意的是,在同一个包里面的protected域和default域中,需要掌握的规则为:
[1]protected域本身是为了对象继承而设计的,所以只要满足继承关系的时候protected是可以访问的,而不去管两个类是否在同一个包内
[2]default域本身就是包域,所以上边的表格里面写的不可访问前提条件为子类成员不在同一个包内,即如果子类成员在同一个包内,default域是可以访问的,谨记:default域为包域
4)Java类修饰符[不包含内部类]
Java里面外部类修饰符只有两种:公共类(使用public关键字)、友好类(不使用任何关键字)
1.公共类只要被导入过后,任何一个类都可以访问该类,至于类中的成员按照变量访问域来规范,前提是你要可以访问该类才能访问类中的成员
2.友好类只能在同一个包里面访问,其他包里面的类即使导入了该包也只能访问该包里面的共有类,这个符合变量的包域即default域
3.在我们编程过程中,.java文件对应的就是一个class的类名称,当然你可以把一个包里面所有的类都用default修饰,不可排除这种做法完全是在脑残,一个.java文件里面最多拥有一个public修饰的class,而且被public修饰的class必须和.java源文件同名,这是Java语言本身规定的
3.Java涉及OO的一些关键知识点:
1)继承基本概念:
在Java语言里面,如果要实现类的继承有两种方式:类继承(extends)和接口继承(implements),一般情况下,extends用来描述is-a关系,而implements用来描述has-a关系。使用extends关键字标识一个类派生于另外一个类,习惯上,我们把被派生的类成为超类,也就是父类,而派生的类称为子类,根据OO里面多态法则可以知道,子类会具有比超类更多的数据和功能。当一个子类继承了某个父类的时候子类就拥有了超类的域和方法,简单来说,继承看上去类似复制操作。Java中所有的类都直接或者间接继承于Object类,因此可以认为Object是所有Java类的超类。
这两种继承有几个需要注意的点:
【1】类继承为单继承关系,一个类只会存在一个父类,不会有第二个,可以理解为父类的唯一性:一个类只可以继承于另外的一个类
【2】但是接口继承为多继承关系,当一个类实现一个接口的时候,可以同时实现多个接口:一个类可以实现多个接口
【3】接口本身支持多继承关系,其意思为一个接口本身可以从另外几个接口继承过来,接口继承的时候,只能使用extends关键字,不能使用implements关键字来完成接口的继承,字面意思上讲:接口不可以实现接口。
接下来再看一段代码,以下都为合法的写法:
interface AA{}
interface CC{}
interface BB extends AA,CC{} //这是一个接口继承于另外一个接口
class A{}
class B extends A{} //类的单继承
class C extends A implements AA,CC{} //类继承于某个父类而且同时实现多个接口操作,在继承和接口实现同时出现的时候,实现应该写在继承之后
继承(extends)和实现(implements)的规则如下:
extends:子类可以继承父类除开修饰为private的所有属性和方法,当子类需要调用父类的方法或者属性的时候使用super关键字,当子类继承超类的方法的时候,方法修饰的域只能扩大不能缩小,父类里面被标记为final的成员函数同样是不能继承的
implements:子类实现了某个接口过后,必须实现接口中所有的抽象方法[接口中的方法默认全就是抽象的],所有的接口实现方法都必须写出它的实现过程
2)抽象类、接口、final类:
i抽象类——使用abstract作为类的修饰符,一旦被abstract修饰的类就为抽象类,抽象类表示该类里面可以仅仅包含一些方法的定义,可以不需要该方法的实现。抽象类里面可以定义抽象方法,使用abstract修饰符进行定义,其使用方法为:
[1]在具体类继承抽象类时,必须覆盖该类里面的每一个抽象方法,而每个已实现的方法对应的方法签名和抽象类制定的方法必须一样
[2]当父类已经有实际功能的方法时,该方法在子类中可以不实现,直接引用该方法就好,但是子类也可以重写该父类的方法
[3]抽象类不可以实例化,但是并不代表抽象类不可以有构造函数
[4]当抽象类继承抽象类时,可以不用完全覆盖该类里面的每个抽象方法,也可以实现一部分,或者完全不去实现都可以
这里需要提醒一点就是:可以理解为抽象类的定义本身设计是为了让别的类继承该类而设计的,而在别的类继承抽象类的过程中,直到该抽象类里面定义的所有抽象方法都实现了才能使用该具体类,有一条法则必须牢记:当一个类里面的方法为抽象方法时,该类一定是抽象类,当一个类是抽象类时,里面的方法不一定是抽象方法或者说这个类里面不一定包含了抽象方法。
先看一段代码来理解整个流程:
abstract class BaseUser{
//此方法为抽象类里面的具体方法
public void helloImpl(){ System.out.println("Hello"); }
//此种方法定义方式为抽象类里面抽象方法的定义方式,直接在函数后边使用“;”而不带任何函数体
public abstract void helloAbstract();
public abstract void helloSecondAbstract();
}
/**
*UserOne类继承于抽象类BaseUser,尽管UserOne本身也属于抽象类,
*但是该类已经实现了BaseUser里面的所有方法,所以:抽象类里面不一定包含了抽象方法
*/
abstract class UserOne extends BaseUser{
public void helloAbstract(){……}
public void helloSecondAbstract(){……}
}
/**
*UserTwo类继承于抽象类BaseUser,UserTwo也属于抽象类,所以该类里面
*还可以继续保留抽象方法helloAbstract(),这个类出现的目的和抽象类本身目的一样为了让其他类来继承
*/
abstract class UserTwo extends BaseUser{
//其实这一行在这个类里面可以不写,因为如果不实现该方法,这种定义已经从父类继承过来了
public abstract void helloAbstract();
public void helloSecondAbstract(){……}
}
/**
*UserThree为具体类,之所以它仅仅实现一个方法helloAbstract()是因为它不是从BaseUser继承
*它从实现了helloSecondAbstract()方法的类UserTwo继承过来
*/
class UserThree extends UserTwo{
public void helloAbstract(){……}
}
/**
*UserFour为一个具体类,它直接从BaseUser抽象类继承过来,所以该类实现了里面的所有抽象方法
*/
class UserFour extends BaseUser{
public void helloAbstract(){……}
public void helloSecondAbstract(){……}
}
ii接口——接口可以理解为一个特殊的抽象类,在Java里面不使用abstract来定义,直接使用interface关键字定义,对于interface特性的掌握,通过比较的方式来进行,下边为抽象类和接口的区别:
[1]抽象类里面可以拥有具体的方法实现,接口不可以有,接口里面所有的方法都是抽象方法
[2]接口没有构造函数,而抽象类拥有一个系统默认的无参数构造函数
[3]接口没有内置的this和super变量,而抽象类里面拥有这两个内置变量
[4]接口的成员变量一定是常量,我们又称为接口常量,而abstract类的成员变量就是一般变量
[5]接口的成员函数的修饰符均为public,而抽象类的成员函数的修饰符不做限制
先看一段代码:
abstract interface A{
//接口常量的定义,别忘记了需要初始化
public static final int A_INT = 0;
//接口中的接口方法的定义,这方法默认就属于抽象方法
public abstract void fun();
}
在上边代码段里面,定义了一个接口A,而灰色部分内容是可写可不写的,因为灰色部分写不写的效果是一样的,上边代码段的定义和下边这段是等价的:
interface A{
int A_INT = 0;
void fun();
}
一般情况都是用以上简化的定义方式,其意思可以这样理解:只要我们在定义接口的时候语法没有错,那么JVM会为该接口自动赋对应的接口修饰符,使得接口定义为第一种方式,所以二者等价
iii.final关键字——final关键字一般有以下几种用法:
[1]当final用于变量的时候,如果该变量为一个基础变量,即《Java基本数据类型》里面讲到的八种基本变量时,表示该变量存在内存里面的值为一个常量,不可更改
[2]当final用于一个方法的时候,表示该方法不可以被继承,即使该方法为public修饰符,这个方法也不可以被子类继承,只能被子类调用
[3]当final用于一个类定义的时候,表示该类不可以有子类,这里可以引申一点:abstract和final两个关键字是不可以同时出现的
[4]当final用于变量的时候,如果该变量为一个符合变量,即Java中继承于Object的变量,表示该引用不可以指向其他的对象,但是并不代表该引用指向的对象不可更改
3)重载和重写:
i重载(Overloading)——方法重载是让类以统一的方式处理不同类型数据的一种手段,Java里面的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但是却具有不同的参数列表和不同的定义,调用该方法的时候,通过使用参数的类型和个数来判断需要调用哪个函数,这个地方也体现了类里面的针对方法的多态设计,在方法重载里面,需要注意的有几点:
[1]在使用重载的时候,只能通过不同的参数表,比如:不同的参数类型、不同的参数个数、不同的参数顺序,来区别二者是否重载
[2]不能通过访问权限、返回值、抛出的异常来进行函数重载
[3]方法的异常类型和数目对重载本身没有影响
[4]针对Java中的继承而言,如果某个方法在父类中的修饰符是private,那么就不能在子类中对其进行重载,如果定义的话,子类是定义了一个新方法,不会达到重载效果
还有一点需要注意的是:函数重载可能会遇到几个特殊情况,比如实参转型、返回值转型、不定参数重载【JDK 5.0以上】,这三种情况在考虑的时候需要详细检查一下,基本规则就和Java语言的转型规则是一样的。
ii重写(Overriding)——Java语言中,子类可以继承父类中的方法,而不需要重新编写该方法,但是有时候子类可能会在父类同样的方法上做一定的修改,这样就需要采用方法重写,方法重写有时候可以定义为覆盖。如果子类中的方法签名与父类中的方法签名一模一样,则该方法就会覆盖父类中的方法,若要调用父类中的方法,可以使用super关键字。
在方法重写中需要注意几个关键的内容:
[1]覆盖的方法签名必须和被覆盖的方法的签名完全匹配,才能达到覆盖的效果
[2]覆盖的方法的返回值也必须和被覆盖的方法的返回值是一致的
[3]覆盖方法所抛出的异常和被覆盖的方法抛出的异常一致,或者是其子类异常才可以
[4]若父类中的方法为private,在子类中使用覆盖的时候是没有效果的,这个时候子类只是定义了一个新方法,却没有进行覆盖操作
接下来看几段比较不容易理解的典型的代码【普通代码省略】:
class A{
private final void A(){
System.out.println("Super Hello");
}
}
class B extends A{
private final void A(){
System.out.println("Sub Hello");
}
}
以上代码里面,没有出现覆盖,原因是父类的private方法本身是不可以被继承的,覆盖满足的条件必须是子类继承了父类的方法才能够被新的定义覆盖,上边代码段子类只是定义了一个新方法,不存在覆盖现象。由此可知,上边的代码是可以通过编译的,而且使用的时候不会出错。
class A{
private void A(){}
}
class B extends A{
/**这句话可以编译通过,但是这里并没有重
*载父类的方法,所以针对A类而言不存在函数重载现象
**/
public void A(int a){……}
/**这句话也可以编译通过,按照重载的法则,仅仅包含了不同
*的返回值是不能算重载的,这种情况是没有办法通过编译的,但是这句话可以通过编译
*原因在于父类的函数修饰符为private,所以这里并没有重载,而这里重载的函数只是
*子类的A(int)函数,而且这里不存在重写,所以这段代码是完全符合逻辑的一段代码
**/
public int A(){……}
}
从整体意义上讲,上边代码仅仅出现了一次重载操作,即是子类本身进行了重载,因为A函数的参数签名不一样,一个参数是int,一个是空参数
4)对象的拷贝[深拷贝和浅拷贝]:
i.关于clone[对象拷贝]——在实际编程过程,有时候我们会遇到一种情况:当你有一个对象A,在某一个时刻,A已经保存了对应的属性值,而且这些值本身是有效的,这个时候可能需要一个和A完全相同的对象B,并且当B里面的属性值发生变化的时候,A中的属性值不受影响,可以理解为A和B独立,但是B的初始化不是按照我们平时创建该对象的时候的初始化操作,B的初始化数据完全来自A。对Java存储模型了解的人都明白,在Java里面如果针对两个对象引用采取赋值操作的时候,仅仅是让两个引用指向了同一对象,如果其中一个引用里面的对象属性改变的时候会影响另外一个对象属性跟着改变,所以Java语言本身的对象赋值语句是不能完成上边的需求的。在这种时候,就需要用到Object类里面的通用方法clone(),这里需要说明的是:
通过clone()方法创建的对象是一个新对象,它可以认为是源对象的一个拷贝,但是在内存堆中,JVM会为这个拷贝分配新的对象存储空间来存放该对象的所有状态
该拷贝和普通对象使用new操作符创建的对象唯一的区别在于初始值,这个拷贝的初始值不是对象里面成员的默认值,而是和源对象此刻状态的成员的值是一样的
下边这段代码是clone方法的运用:
public class Testing {
public static void main(String args[]){
AClass class1 = new AClass();
class1.a = 12;
AClass class2 = (AClass)class1.clone();
System.out.println(class2.a);
System.out.println(class1==class2);
}
}
class AClass implements Cloneable{
public int a = 0;
public Object clone(){
AClass o = null;
try{
o = (AClass)super.clone();
}catch(CloneNotSupportedException ex){
ex.printStackTrace();
}
return o;
}
}
上边这段代码运行结果输出为:
12
false
可以知道的就是成功复制了一个AClass的对象,该对象的引用为class1,而拷贝对象的引用为class2,这两个引用通过==比较输出为false,证明这两个引用不是指向了同一个对象,而且拷贝对象里面的a的值和class1引用的对象里面的a的值是一样的,都是12,这样就成功完成了对象的拷贝过程。若你对上边这段代码还有不了解的地方可以尝试将下边的代码修改掉:
AClass class2 = (AClass)class1.clone() 修改为:AClass class2 = class1;
改了过后,输出结果应该为:
12
true
所以在对象的clone过程,需要注意的几点有:
[1]希望能够提供对象clone功能的类必须实现Cloneable接口,这个接口位于java.lang包里面
[2]希望提供对象clone功能的类必须重载clone()方法,在重载过程可以看到这句话:super.clone();也就是说,不论clone类的继承结构如何,我们在对象拷贝的时候都直接或简介调用了Object的clone()方法。而且细心留意可以看到Object的clone方法是protected域的,也就是说这个方法只有Object的子类可以调用,而在重载的时候将clone方法修饰符改为public
[3]还有一点很重要就是Object源代码里面的clone()方法是native方法,一般而言,对JVM来说,native方法的效率远比java中的普通方法高,这就是为什么我们在复制一个对象的时候使用Object的clone()方法,而不是使用new的方式。
[4]Cloneable接口和我们在编写IO程序的时候序列化接口一样,只是一个标志,这个接口是不包含任何方法的,这个标志主要是为了检测Object类中的clone方法,若我们定义的类想要实现拷贝功能,但是没有实现该接口而调用Object的clone方法,那么就会出现语句中catch块里面的异常错误,抛出CloneNotSupportedException。
ii浅拷贝——在对象clone的过程中,浅拷贝又称为“影子clone”,先看一段代码:
//这里先定义一个类
class AClass{
public int a;
public AClass(int a){ this.a = a;}
public void change(){ a += 12;}
public String toString(){ return "A Value is " + this.a;}
}
//定义一个clone类,里面包含了AClass的对象引用
class BClass implements Cloneable{
public int a = 12;
public AClass obj = new AClass(11);
public Object clone(){
BClass object = null;
try{
object = (BClass)super.clone();
}catch(CloneNotSupportedException ex){
ex.printStackTrace();
}
return object;
}
}
public class TestClone {
public static void main(String args[]){
BClass class1 = new BClass();
class1.a = 15;
System.out.println(class1.a);
System.out.println(class1.obj);
BClass class2 = (BClass)class1.clone();
class2.a = 22;
class2.obj.change();
System.out.println(class1.a);
System.out.println(class1.obj);
System.out.println(class2.a);
System.out.println(class2.obj);
}
}
运行上边这段代码会有以下输出:
15
A Value is 11
<spa
分享到:
相关推荐
《物联网标识体系-对象分类规范》(国标草案1017).pdf
证券公司信息技术管理规定草案 (2).pdf证券公司信息技术管理规定草案 (2).pdf证券公司信息技术管理规定草案 (2).pdf证券公司信息技术管理规定草案 (2).pdf证券公司信息技术管理规定草案 (2).pdf证券公司信息技术管理...
Hibernate 是一种Java语言下的...Hibernate不仅负责从Java类到数据库表的映射(还包括从Java数据类型到SQL数据类型的映射),还提供了面向对象的数据查询检索机制,从而极大地缩短的手动处理SQL和JDBC上的开发时间。
jose:JavaScript 对象签名和加密草案的实现
草案涉及到两部分,一部分是要求类,另一部分是考核类,要求类是日常设计、开发或运维等工作中需要遵守且对中心内部比较重要的指标或事项,考核类主要是影响业务正常开展的相关指标,系统的不可用、不及时、不准确等...
校园和市政网络............................................................................................. 9 语音性能改善.................................................................................
上海市促进生活垃圾分类减量管理办法(草案) (2).pdf上海市促进生活垃圾分类减量管理办法(草案) (2).pdf
国家标准信息安全技术ICT供应链安全风险管理指引草案编制 (2).pdf国家标准信息安全技术ICT供应链安全风险管理指引草案编制 (2).pdf国家标准信息安全技术ICT供应链安全风险管理指引草案编制 (2).pdf国家标准信息安全...
国家标准信息安全技术ICT供应链安全风险管理指引草案编制 (2).docx国家标准信息安全技术ICT供应链安全风险管理指引草案编制 (2).docx国家标准信息安全技术ICT供应链安全风险管理指引草案编制 (2).docx国家标准信息...
五一车展策划方案草案_2.ppt
黄金资源广告招标书现场招标竞购部分草案.doc
《信息技术 服务管理 第1部分:规范》草案 071212 本标准由国家标准化管理委员会提出。 本标准由全国信息技术标准化技术委员会归口
在2013年发布的 JavaSE8 中包含一个叫做 Lambda Project 的计划,在 JSR-335 草案 中有描述。 JSR-335 将闭包引入了 Java 。闭包在现在的很多流行的语言中都存在,例如 C++、C# 。闭包允许我 们创建函数指针,并把...
茶楼人力规划及部分规章制度草案.docx
2008年最新802.11草案,介绍了最新的WIFI协议标准,该标准不支持WPA中的TKIP加密方法!
oa办公系统需求草案.doc我们大致整理了下该协同办公系统的功能需求。系统功能主要分为文档管理、项目管理、工作计划、消息管理、用户管理、权限管理和系统配置这七大功能。
基础类实现为java.nio ,它允许使用非阻塞事件驱动模型(类似于Web浏览器的 )。 已实现的WebSocket协议版本为: 有关协议版本/草案的更多详细信息。 启用同时引用服务器和客户端示例的扩展。 入门 依赖管理工具 ...