---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
三:面向对象
1, 面向对象
1. 面向过程 强调过程,执行者
2. 面向对象 强调对象,指挥者
特点:
1)将复杂的事情简单化。
2)面向对象将以前的过程中的执行者,变成了指挥者。
3)面向对象这种思想是符合现在人们思考习惯的一种思想。
过程和对象在我们的程序中是如何体现的呢?过程其实就是函数;对象时将函数等一些内容进行了封装。简而言之就是:谁拥有数据,谁就对外提供操作这些数据的方法。
面向对象的特征:继承(Inheritance)、封装(Encapsulation)、多态(Polymorphism).
2, 类和对象
1. 类 对现实世界中实物的描述(属性和方法) Person p = new Person();
2. 对象 现实世界中实际存在的具体个体
3. 对象的使用以及内存图
3, 局部变量和成员变量
1. 作用范围
局部变量:方法内
成员变量:类中,对整个类有效
2. 存储空间
局部变量:栈内存
成员变量:堆内存
3. 初始化值
局部变量:在使用前必须手动赋值
成员变量:JVM默认初始化值
4, 匿名对象的使用
1. 当对象中的功能只执行一次的时候使用,否则,请使用有名字的对象
Person p = new Person();
p.show();
p.print();
new Person().show();
new Person().print();
method(new Person());
2. 用于作为实际参数进行传递
method(Person pp){}//method(p);//地址值
method(new Person());//地址值
method(p);
在类中定义其实都称之为成员。成员有两种:
1) 成员变量:其实对应的就是事物的属性。
2) 成员函数:其实敌营的就是事物的行为。
所以其实定义类,就是在定义成员变量和成员函数。但是在定义前,必须先要对事物进行属性和行为的分析,才可以用代码来体现。
5, 封装(Encapsulation)
1. 封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
2. 好处:将变化隔离;便于使用;提高重用性;提高安全性。
3. 封装原则:将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共方法对其访问。
4. 函数,类,包和框架都是封装体。
5. private关键字:private是一种权限修饰符,用于修饰成员(成员变量和成员函数),被私有化的成员只在本类中有效。
(1) 将成员变量私有化,对外提供对应的set,get方法对其进行访问,提高对数据访问的安全性;
(2) 将属性私有化以后,类以外即使建立了对象也不能直接访问;
(3) 私有仅仅是封装的一种表现形式,权限在访问不到的范文都是封装。
(4) 在访问方式中加入逻辑判断语句,提高代码健壮性。
(5) 若一个类中有setAge()和getAge()两个功能,那么该类中肯定有个私有属性age。其中set,get根据返回值类型而定;而成员变量有初始化值,局部变量则没有。
总结:开发时,属性石用于存储数据的,直接被访问,容易出现安全隐患,所以,类中的属性通常被私有化,并对外提供公共的访问方式。这个方法一般有两个,规范写法:对于属性xxx,可以使用setXxx()和getXxx()对其操作
6. 类中怎么没有定义主函数?
主函数的存在,仅为该类是否需要独立运行;如果不需要,主函数是不用定义的。
主函数的解释:保证所在类的独立运行,是程序的入口,被jvm调用。
6, 构造函数
1. 特点:
1) 函数名与类名相同
2) 不用定义返回值类型
3) 不可以写return语句
作用:给对象进行初始化;
注意:默认构造函数的特点,多个构造函数是以重载的形式存在。
对象一建立就会调用与之对应的构造函数,构造函数的作用,是用于给对象进行初始化
2. 构造函数的小细节
当一个类中没有定义构造函数时,那么系统就会默认给该类加入一个空参数的构造函数;当在类中自定义了构造函数后,默认的构造函数就没有了。
3. 构造函数和一般函数在写法上有不同。
在运行上也不同,构造函数时在对象一建立就运行,给对象初始化。而一般方法是对象调用才执行,是给对象添加对象具备的功能。
一个对象建立,构造函数只运行一次,而一般方法可以被该对象调用多次。
4. 什么时候定义构造函数呢?
当分析事物时,该事物存在就具备了一些特性或者行为,那么僵这些内容就定义子构造函数里。
5. 构造函数代码块
作用:给对象进行初始化。
对象一建立就运行,而且优先于构造函数执行。
和构造函数的区别:
构造代码块是给所有对象进行统一初始化,而构造函数是给对应对象初始化。
6. Person p =new Person();创建一个对象都在内存中做了什么事情?
1) 现将硬盘上指定位置的Person.class文件加载进内存;
2) 执行main方法时,在栈内存中开辟了main方法的空间(压栈—>进栈),然后在main方法的栈区分配了一个变量p;
3) 在堆内存中开辟了一个实体空间,分配了一个内存首地址值。new
4) 在该实体空间中进行属性的空间分配,并进行了默认初始化
5) 对空间中的属性进行显示初始化
6) 进行实体的构造代码块初始化
7) 调用该实体对应的构造函数,进行构造函数初始化
8) 将首地址赋值给p,p变量就引用了该实体,并指向了该对象
7, this关键字
1. 代表当前对象的引用。使用的时候,谁调用方法,this就代表谁。
2. 什么时候使用this呢?
(1) 当局部变量和成员变量重名的时候,可以用this进行区分
(2) 如果功能内部使用到了调用该功能的对象,这时就用this来表示这个对象,其中,this还可以用于构造函数间的调用。
3. 调用格式:this(实际参数);
(1) this对象后面跟上.调用的是成员属性和成员方法(一般方法);
(2) this对象后面跟上()调用的是本类中的对应参数的构造函数
注意:用this调用构造函数,必须定义在构造函数的第一行。因为构造函数时用于初始化的,所以初始化动作一定要执行,否则编译失败。
8, static关键字
1. static概述
为了节省堆内存空间,因此就将方法中的共性内容提取出来,用static修饰,节省空间,没有操作特有数据的工具类都是静态方法。
用法:
1) 是一个修饰符,用于修饰成员(成员变量,成员函数)
2) 当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用,格式:类名.静态成员
2. static特点
1) 随着类的加载而加载,也就是说:静态会随着类的消失而消失,其生命周期最长。
2) 优先于对象存在。明确一点:静态时先存在的,对象是后存在的。
3) 被所有对象所共享。
4) 可以直接被类名.调用。
3. 弊端
1) 有些数据是对象特有数据,是不可以被静态修饰的。因为那样的话,特有数据会变成对象的共享数据,这样对事物的描述就除了问题,所以在定义静态时,必须要明确,这个数据是否是被对象所共享。
2) 静态方法只能访问静态成员,不可以访问非静态成员
3) 静态方法中不能使用this,super关键字,因为this代表对象,而静态存在时,有可能还没有对象,所以this无法使用
4) 主函数是静态的
4. 什么时候定义静态成员呢?或者说:定义成员时,到底需不需要被静态修饰?
成员分两种:
1) 成员变量(数据共享时静态化)
该成员变量的数据是否是所有对象都一样:
如果是,那么该变量需要被静态修饰,因为是共享的数据;
如果不是,那么就说明这是对象的特有数据,要存储到对象中。
2) 成员函数(方法中没有调用特有数据时就定义成静态)
如何判断成员函数是否需要被静态修饰呢?
只要参考该函数内是否访问了对象中的特有数据:
如果有访问特有数据,那该方法不能被静态修饰;
如果没有访问过特有数据,那么这个方法需要被静态修饰。
5. 成员变量和静态变量的区别:
1) 成员变量所属于对象,所以也成为实例变量
静态变量所属于类,所以也成为类变量
2) 成员变量存在于堆内存中;
静态变量存在于方法中。
3) 成员变量随着对象创建而存在,随着对象被回收而消失
静态变量随着类的加载而加载,随着类的消失而消失
4) 成员变量只能被对象所调用;
静态变量可以被对象调用,也可以被类名调用
所以,成员变量可以成为对象的特有数据,静态变量称为对象的共享数据。
6. 静态代码块:
就是一个有静态关键字标识的一个代码块区域,定义在类中。
作用:可以完成类的初始化。静态代码块随着类的加载而加载,而且只执行一次(new 多个对象就执行一次)。如果和主函数在同一个类中,优先于主函数执行。
public :访问权限最大
static:不需要对象,直接类名.即可
void :主函数没有返回值
main:主函数的特定名称
(String[] args):主函数的参数,是一个字符串数组类型的参数,jvm调用main方法时,传递的实际参数式new String[0]
Jvm默认传递的长度为0的字符串数组,我们在运行该类时,也可以指定具体的参数进行传递。可以在控制台,运行该类时,在后面加入参数。参数之间通过空格隔开。Jvm会自动将这些字符串参数作为args数组中的元素,进行存储。
静态代码块、构造代码块、构造函数同时存在时的执行顺序:
静态代码块 --> 构造代码块 -->构造函数
7. 静态的应用
每一个应用程序都有共性的功能,可以将这些功能进行抽取,独立封装,一边复用,虽然可以通过建立ArrayTool对对象使用这些工具方法,对数组进行操作,却发现了问题:
1) 对象用于封装数据的,可是ArrayTool对象并未封装的特有数据;
2) 操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。
这时就考虑,让程序更严谨,是不需要对象的。可以将ArrayTool中的方法都定义成static的,直接通过类名调用即可。将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象,为了更为严谨,强制让该类不能建立对象,可以通过将构造函数私有化即可。
8. 生成Java帮助文档
命令:javadoc -d myhelp -author -version ArrayTool.java
/** //格式
*类描述
*@author 作者名
*@version 版本号
*/
/**
*方法描述
*@param 参数描述
*@return 返回值描述
*/
9,单例设计模式
Java中有23中设计模式,其中单例设计模式最为常见
单例设计模式作用:保证类在内存中只有一个对象。
如何保证类在内存中只有一个对象呢?
1) 控制类的创建,不让其他类类创建本类对象,private
2) 在本类中定义一个本类对象。Single s
3) 提供公共的访问方式.
单例设计模式的格式:
1. 恶汉式
classSingle(){
//1.私有构造函数
private Single(){}
//2.在本类中创建并私有本类对象
private static Single s = new Single();
//3.提供一个公共的访问方法,返回该对象
public static Single getInstance(){
return s;
}
}
2. 懒汉式(延迟加载)
classSingle{
private Single(){}
private static Single s = null;
public static Single getInstance(){
if(s == null)
s = new Single();
}
return s;
}
这种方式也称之为延迟加载,在多线程中需要加入同步代码块才能保证其唯一性,一般开发中都是使用恶汉式的单例设计模式
3. 传说中的第三种单例设计模式
classSingle{
private Single(){}//私有构造函数
public static final Single s = newSingle(){};//对外提供一个公共访问方式
}
小结:定义单例设计模式,建议使用恶汉式,安全,简单,高效。
10, 继承(extends)
1. 继承的体系结构:就是对要描述的事物进行不断的向上抽取,就出现了体系结构
1) 要了解这个体系结构中最共性的内容,就看最顶层的类。
2) 要使用这个体系的功能,就用最底层的类创建对象。
2. 继承的好处:
1) 继承的出现,提高了代码的复用性
2) 继承的出现,让类与类之间产生了关系,用extends来表示,这个关系的出现,为后面的多态打下了基础。
3. 特点:
1) Java只支持单继承(其实确切的说是java对多继承进行了优化,避免了安全问题)
2) Java支持多重(层)继承
4. 注意:
1) 子类可以直接访问父类中的非私有的属性和行为
2) 不要仅为了获取其他类中部分功能而去继承。
3) 类与类之间要有所属(“is a”)关系,xx1是xx2的一种。
如何判断A和B是否有继承关系?
A如果继承B,那么就可以说A是B的一种
为什么Java不支持多继承呢?
因为当一个类同时继承两个父类时,两个父类中有相同的功能,那么额子类对象调用该功能时,运行哪一个呢?因为弗雷中的方法中存在方法体。
但是Java支持多重(层)成,有了继承体系,体系中的顶层父类时通过不断向上抽取而来的。它里面定义了该体系最基本最共性内容的功能。简单的说:对于一个继承体系,查阅顶层父类中的内容,创建最底层子类的对象。
5. 子父类出现后,类中的成员都有了那些特点:
1) 成员变量
当子父类中出现一样的属性时,子类类型的对象,调用该属性,值是子类的属性值。如需调用父类中的属性值,需要使用一个关键字:super
this:代表的是本类类型的对象引用
super:代表是子类所属的父类中的内存空间的引用
注意:子父类中通常是不会出现同名成员变量的,因为父类中只要定义了,子类就不用再定义,直接继承过来即可。
2) 成员函数
当子父类中出现了一模一样的方法时,建立子类对象会运行子类中的方法。好像父类中的方法被覆盖了一样,所以这种情况,就是函数的另一个特性:覆盖(复写,重写)
什么时候使用覆盖呢?当一个类的功能需要修改时,可以通过覆盖来实现。
3) 构造函数
(1) 发现子类构造函数运行时,先运行了父类的构造函数,这是为什么?
因为子类的所有构造函数中的第一行,其实都有一条隐式的语句:super();
super():表示父类的构造函数,并会调用与参数相对应的父类中的构造函数。而super()是在调用父类中空参数的构造函数。
(2) 为什么子类对象初始化时,都需要调用父类中的构造函数?(为什么要在子类构造函数的第一行加入这个super()?)
因为子类继承父类,会继承到父类中的数据,所以必须要看父类时如何对自己的数据进行初始化的。所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程。
注意:
(1) 子类中所有的构造函数都会默认访问父类中的空参数的构造函数,因为每一个子类构造方法第一行都有隐式的语句super();
(2) 如果父类中没有空参数的构造函数,那么子类的构造函数内,必须通过super语句指定要访问的父类中的构造函数。
(3) 如果子类构造函数中用this来指定调用子类自己的构造函数,那么背调用的构造函数也一样会访问父类中的构造函数。
问题1:super()和this()是否可以同时出现在构造函数中?
解答:两个语句只能由一个定义在第一行,所以只能出现其中一个。
问题2:super()或者this()语句为什么一定要定义在第一行?
解答:因为super()或者this()都是调用构造函数,构造函数用于初始化,所以初始化的动作要先完成。
6. 继承的细节:
1) 什么时候使用继承呢?
当类与类之间存在着所属关系时,才具备了继承的前提。a是b中的一种,a继承b,狼是犬科中的一种,英文书中所属关系: “is a”
判断所属关系,可以简单看,如果继承后,被继承的类中的功能,都可以被该子类所具备,那么继承成立;如果不是,不可以继承。
2) 在方法覆盖时,需要注意两点:
(1) 子类覆盖父类时,必须要保证,子类方法的权限必须大于等于父类方法权限才可以实现继承,否则编译失败。
(2) 覆盖时,要么都静态,要么都不静态。(静态只能覆盖静态,或者被静态覆盖)
继承的一个弊端:打破了封装性。对于一些类,或者类中的功能,是需要被继承,或者复写的。这时该如何解决问题呢?一个关键字:final,最终。
3) final特点:
(1) 这个关键字是一个修饰符,可以修饰类,方法和变量
(2) 被final修饰的类是一个最终类,不可以被继承;
(3) 被final修饰的方法是一个最终方法,不可以被覆盖;
(4) 被final修饰的变量时一个常量,只能赋值一次。
11,抽象类(abstract)
1. 抽象:不具体,看不明白,抽象类表象体现。
在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字abstract所标识,声明为抽象方法。抽象方法所在类一定要标识为抽象类,也就是说该类需要被abstract关键字所修饰。
2. 抽象类的特点:
1) 抽象方法只能定义在抽象类中,抽象类和抽象方法必须由abstract关键字修饰(可以描述类和方法,不可以描述变量)
2) 抽象方法之定义方法声明,并不定义方法实现。
3) 抽象类不可以被创建对象(实例化)
4) 只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化;否则,该子类还是一个抽象类。
3. 抽象类的细节:
1) 抽象类中是否有构造函数?有,用于给子类对象进行初始化。
2) 抽象类中是否可以定义非抽象方法?
可以;其实抽象类和一般类没有太大区别,都是在描述事物,只不过抽象类在描述事物时,有些功能不具体,所以抽象类和一般类在定义上,都是需要定义属性和行为的。只不过比一般类对了一个抽象函数,而且比一般类少了一个创建对象的部分。
4. 抽象关键字abstract和那些关键字不能共存?final、private、static
5. 抽象类中可不可以不定义抽象方法?
可以,抽象方法仅仅是为了不让该类创建对象。
12,模板方法设计模式
解决的问题:当功能内部一部分实现是确定,一部分实现是不确定的时候,这是可以把不确定的部分暴露出去,让子类去实现。代码如下:
class Test1 {
publicstatic void main(String[] args) {
GetTimegt = new SubDemo();//创建父类的引用并指向子类对象
gt.getTime();
}
}
abstract class GetTime{
publicfinal void getTime(){//此功能如果不需要复写,可加final限定
longstart = System.currentTimeMillis();
runCode();//不确定的功能部分,提取出来,通过抽象方法实现
longend = System.currentTimeMillis();
System.out.println((end- start) + "毫秒");
}
publicabstract void runCode();//抽象不确定的功能,让子类复写实现
}
class SubDemo extends GetTime{
publicvoid runCode(){//子类复写功能方法
for(inti=0; i<100; i++){
System.out.print("i="+ i + "\r\n");
}
}
}
13,接口(interface)
1. 接口的由来:当一个类中所有的方法都是抽象的时候,没必要定义为抽象类,定义为接口即可。
2. 解决了Java中只能单继承的问题(对多继承进行了优化)
1) 类与类:只能是单继承,extends
2) 接口与接口:可以是单继承,也可以是多继承,extends
3) 类与接口:可以是单实现,也可以是多实现,implements
3. 成员特点:
1) 只有成员变量和成员方法
2) 成员变量,默认修饰符 public static final
3) 成员方法,默认修饰符public abstract
4. 接口的特点:(可以理解为电脑主板上提供的接口)
1) 接口式对外暴露的规则
2) 接口式功能的扩展
3) 接口可以用来多实现
4) 接口与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口
5) 接口与接口之间可以有继承关系
6) 接口的出现降低了程序之间的耦合性
5. 接口中有抽象方法,说明接口不可以实例化。接口的子类必须实现了接口中所有的抽象方法后,该子类才可以实例化;否则,该子类还是一个抽象类。
6. 抽象类与接口:
抽象类:一般用于描述一个体系单元,将一组共性内容进行抽取,特点:可以在类中定义抽象内容让子类实现,可以定义非抽象内容让子类直接使用。它里面定义的都是一些体系中的基本内容。
接口:一般用于定义对象的扩展功能,是在继承之外还需这个对象具备的一些功能。
抽象类和接口的共性:都是不断向上抽取的结果。
7. 抽象类和接口的区别
1) 抽象类智能被继承,而且智能单继承;
接口需要被实现,而且可以多实现。
2) 抽象类中可以定义非抽象方法,子类可以直接继承使用;
接口中都有抽象方法,需要子类去实现。
3) 抽象类使用的是 is a关系;
接口使用的是like a关系。
4) 抽象类的成员修饰符可以自定义;
5) 接口中的成员修饰符是固定的,全是public。
在开发之前,先定义规则,A和B分别开发,A负责实现这个规则,B负责使用这个规则。至于A是如何规则具体实现的,B是不需要知道的,这样这个接口的出现就降低了A和B的直接耦合性。
14,多态(Polymorphism):函数本身就具备多态性,某一种事物有不同的具体的体现
体现:父类引用或者接口的引用指向了自己的子类对象。//Animal a = new Cat();
多态的好处:提高了程序的扩展性。
多态的弊端:当父类引用指向子类对象时,虽然提高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。(前期不能使用后期产生的功能,即访问的局限性)
多态的前提:
1) 必须要有关系,比如继承或者实现。
2) 通常会有覆盖操作。
多态的出现思想上也坐着变化:以前是创建对象并指挥对象做事情。有了多态以后,我们可以找到对象的共性类型,直接操作共性类型做事情即可,这样可以指挥一批对象做事情,即通过操作父类或接口实现。
代码演示:
class 毕姥爷{
void 讲课(){
System.out.println("企业管理");
}
void 钓鱼(){
System.out.println("钓鱼");
}
}
class 毕老师 extends 毕姥爷{
void 讲课(){
System.out.println("JAVA");
}
void 看电影(){
System.out.println("看电影");
}
}
class {
public static void main(String[] args) {
毕姥爷 x = new 毕老师(); //毕老师对象被提升为了毕姥爷类型。
// x.讲课();
// x.看电影(); //错误.
毕老师 y = (毕老师)x; //将毕姥爷类型强制转换成毕老师类型。
y.看电影();//在多态中,自始自终都是子类对象在做着类型的变化。
}
}
如果想用子类对象的特有方法,如何判断对象时哪个具体的子类类型呢?
可以通过一个关键字:instanceof;//判断对象是否实现了指定的接口或继承了指定的类
格式:(对象 instanceof 类型),判断一个对象是否所属于指定的类型。
例如: Student instanceofPerson = true//Student 继承了Person类。
多态在子父类中成员上的体现特点:
1. 成员变量:在多态中,子父类成员变量同名。
在编译时期:参考的是引用型变量所属的类中是否有调用的成员。(编译时不产生对象,只检查语法错误)
在运行时期:也是参考引用型变量所属的类中是否有调用的成员。
简而言之:无论编译和运行,成员变量参考的都是引用变量所属的类中的成员变量,即成员变量,编译运行都看左边。
2. 成员函数。
编译时期:参考引用型变量所属的类中是否有调用的方法
运行时期:参考的是对象所属的类中是否有调用方法
为什么是这样的呢?
因为在子父类中,对于一模一样的成员函数,有一个特性:覆盖。
简单一句话:成员函数,编译看引用型变量所属的类,运行看对象所属的类,即成员函数,编译看左边,运行看右边
3. 静态函数
编译时期:参考的是引用型变量所属的类中是否有调用的成员。
运行时期:参考的也是引用型变量所属的类中是否有调用的成员。
为什么是这样的呢?
因为静态方法,其实不属于预想,而是所属于该方法所在的类。
调用静态的方法引用是哪个类的引用,调用的就是哪个类中的静态方法。
简单说:静态函数,编译运行都看左边。
经典代码体现:
//需求:电脑运行实例,电脑运行基于主板。
//定义一个接口,用于扩展PCI功能
interface PCI{
//分别定义打开和关闭功能的抽象方法
publicvoid open();
publicvoid close();
}
//创建一个主板类
class MainBoard{
publicvoid run(){
System.out.println("mainboardrun");
}
publicvoid usePCI(PCI p) {//PCI p = new NetCard()//接口型引用指向自己的子类对象。
if(p!=null){
p.open();
p.close();
}
}
}
//让网卡NetCard实现PCI接口,并复写里面的方法
class NetCard implements PCI{
publicvoid open(){
System.out.println("netcardopen");
}
publicvoid close(){
System.out.println("netcardclose");
}
}
class SoundCard implements PCI{
publicvoid open(){
System.out.println("soundcardopen");
}
publicvoid close(){
System.out.println("soundcardclose");
}
}
class DuoTaiDemo4 {
publicstatic void main(String[] args) {
//创建主板对象
MainBoardmb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(newNetCard());
mb.usePCI(newSoundCard());
}
}
15,Object类
Object:所有类的直接或者间接父类,Java认为所有的对象都具备一些基本的共性内容,这些内容可以不断的向上抽取,最终就抽取到了一个最顶层的类中,该类中定义的就是所有对象都具备的功能。
具体方法:
1. boolean equals(Object obj):用于比较两个对象是否相等,其实内部比较的就是两个对象地址。而根据对象的属性不同,判断对象是否相同的具体内容也不一样。所以在定义类是,一般都会复写equals方法,建立本类特有的判断对象是否相同的依据。
public boolean equals(Object obj){
if(!(obj instance ofPerson))
return false;
Person p =(Person)obj;
return this.age = p.age;
}
2. String toString():将对象变成字符串;默认返回的格式:类名@哈希值= getClass().getName()+’@’+Integer.toHexString(hashCode());
为了对象对应的字符串内容有意义,可以通过复写,建立该类对象自己特有的字符串表现形式。
public String toString(){
return “person:”+age;
}
3. Class getClass():获取任意对象运行时的所属字节码文件对象
4. int hashCode():返回该对象的哈希码值,支持此方法是为了提高哈希表的性能。
通常,equals(),toString(),hashCode()在应用中都会被复写,建立具体对象的特有内容。
16,内部类
1. 内部类概述:将一个类定义在另一个类的里面,对里面那个类就成为内部类(内置类,嵌套类)。
2. 内部类的访问规则:
1) 内部类可以直接访问外部类中的成员,包括私有,之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式:外部类名.this
2) 外部类要访问内部类,必须建立内部类对象。
3. 访问格式:
1) 当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,可以直接建立内部类对象,格式:
外部类名.内部类名 变量名 = new 外部类名.内部类对象();
Outer.Inner in = new Outer.Inner();
2) 当内部类在成员位置上,就可以被成员修饰符所修饰
比如:private,将内部类在外部类中进行封装。
static:内部类就具备了static特性,当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。
问题1:在外部其他类中,如果访问内部类的非静态成员呢?
newOuter.Inner().function();
问题2:在外部其他类中,如何直接访问static内部类的静态成员呢?
Outer.Inner.function();
注意:当内部类中定义了静态成员,该内部类必须是static的。当外部类中的静态方法访问内部类时,内部类也必须是static的。
问题3:为什么内部类可以直接访问外部类中的成员呢?
那是因为内部类中都有一个外部类的引用,这个引用是外部类名.this;内部类可以定义在外部类中的成员位置上,也可以定义在外部类中的局部位置上。当内部类被定义在局部位置上,只能访问局部中被final修饰的局部变量。
内部类编译后的文件名:外部类名$内部类名.java
17,匿名内部类
1. 匿名内部类其实就是内部类的简写格式
2. 定义匿名内部类的前提:内部类必须是继承一个类或者实现一个接口
3. 匿名内部类的格式:new父类名或者接口(){定义子类的内容或者覆盖父类方法}.方法
4. 其实匿名内部类就是一个匿名子类对象,而且这个对象有点“胖”,也可以理解为带内容的对象。
5. 匿名内部类中定义的方法最好不要超过3个
6. 定义匿名内部类,就是为了简化书写,覆盖方法。
面试题:
//1
newObject(){
void show(){
System.out.println(“show run”);
}
}.show();
//2
Object obj= new Object(){
void show(){
System.out.println(“show run”);
}
};
obj.show();
问题:1和2的写法是正确的吗?有区别吗?说出原因
解答:写法都是正确的,1和2都是在通过匿名内部类建立一个Object类的子类对象。区别:
第一个可以编译并正常运行;第二个编译失败,因为匿名内部类是一个子类对象,当用Object的obj引用指向时,就被提升为了Object类型,而编译时检查Object类中是否有show方法,所以编译失败。
练习:
interface Inter{
void method();
}
class Test{
/*
static class Innerimplements Inter{
public void method() {
System.out.println("methodrun");
}
}
*/
//补足代码,使用匿名内部类
static Inter function(){
return newInter()//Inner{
public voidmethod(){
System.out.println("methodrun");
}
};
}
}
class InnerClassTest{
public static voidmain(String[] args) {
//Test.function():Test类中有一个静态的方法function。
//.method():function这个方法运算后的结果是一个对象,而且是一个Inter类型的对象。
//因为只有是Inter类型的对象,才可以调用method方法。
Test.function().method();
/*
Inter in =Test.function();
in.method();
*/
}
}
18,异常
1. 异常:就是程序在运行时出现不正常情况。
异常由来:问题也是现实生活中一个个具体的事物,可以通过Java的类的形式进行描述,并封装成对象。其实就是java对不正常情况进行描述后的对象体现。
2. 异常体系
Throwable
|--Error
|--Exception
Error:
1) 通常出现重大问题如:运行的类不存在或者内存溢出等。
2) 不编写针对代码对其处理
Exception:
1) 在运行时出现的一些情况,可以通过try catch finally处理
Error和Exception的子类名都是以父类名作为后缀。
这个体系中的所有类和对象都具备一个独有的特点:就是可抛性
可抛性体现:就是这个体系中的类和对象都可以被throw和throws两个关键字所操作。
3. 对于问题的划分有两种:一种是严重的问题,一种是非严重的问题。
对于严重的,java通过Error类惊醒描述;对于Error一般不便携针对性的代码对其进行处理。
对于非严重的,java通过Exception类进行描述,对于Exception可以使用针对性的处理方式进行处理。
4. 在开发时,如果定义功能时,发现该功能会出现一些问题,应该将问题在定义功能时标识出来,这样调用者就可以在使用这个功能的时候,预先给出处理方式。
如何标识呢?通过throws关键字完成,格式:throws 异常类名,异常类名…这样标识后,调用者在使用该功能时,就必须要处理,否者编译失败
5. 处理方式有两种:1) 捕捉;2) 抛出
对于捕捉:java有针对性的语句块进行处理:
try{
需要被检测的代码;
}catch(异常类 变量名){
异常处理代码;
}finally{
一定会执行的代码;
}
其中,对于异常的处理代码如下:
catch(Exception e){
System.out.println(“message:”+e.getMessage());//获取的是异常的信息
System.out.println(“toString:”+e.toString());//获取的是异常的名字和异常的信息
e.printStackTrace();//打印异常在堆栈中信息;异常名称+异常信息+异常的位置
}
6. 异常处理原则:功能抛出几个异常,功能调用如果进行try处理,需要与之对应的catch处理代码快,这样处理有针对性,抛几个就处理几个。
特殊情况:try对应多个catch时,如果父类的catch语句块,一定要放在下面。
7. throw和throws关键字的区别:
throw用于抛出异常对象,后面跟的是异常对象,throw用在函数内;
throws用于抛出异常类,后面跟的是异常类名,可以有多个,用逗号隔开,throws用在函数上。
通常情况:函数内容如果有throw,抛出异常对象,并没有进行处理,那么函数上一定要声明,否则编译失败,但也有特殊情况。
8. 异常分为两种:
1) 编译时被检查的异常,只要是Exception及其子类都是编译时被检测的异常。
2) 运行时异常,其中Exception有一个特殊的子类RuntimeException,以及RuntimeException的子类是运行异常,也就是说这个异常是编译时不被检查的异常。
9. 编译时被检查的异常和运行时异常的区别:
编译被检查的异常在函数内被抛出,函数必须要声明,否则编译失败。
声明的原因:是需要调用者对该异常进行处理。
运行异常如果在函数内被抛出,在函数上不需要声明。
不声明的原因:不需要调用者处理,运行时异常发生,已经无法再让程序继续运行,所以,不让调用处理的,直接让程序停止,由调用者对代码进行修正。
10.定义异常处理时,什么时候定义try,什么时候定义throws呢?
功能内部如果出现异常,如果内部可以处理,就用try;
如果功能内部处理不了,就必须声明出来,让调用者处理。
11.自定义异常:当开发时,项目中出现了java中没有定义过得问题时,这是就需要我们按照java异常建立思想,将项目中的特有问题也进行对象的封装,这个异常,就成为自定义异常。
对于除法运算,0作为出书是不可以的。java中对这种问题用ArithmeticException类进行描述。对于这个功能,在我们项目中,出书除了不可以为0外,还不可以为负数。可是负数的部分java并没有针对描述,所以我们就需要自定义这个异常。
12.自定义异常的步骤:
1) 定义一个子类继承Exception或者RuntimeException,让该类具备可抛性。
2) 通过throw或者throws进行操作。
自定义异常代码演示:
class FuShuException extends Exception{//自定义异常必须集成Exception体系
private int value;
FuShuException(Stringmsg,int value){
super(msg);
this.value =value;
}
public int getValue(){
returnvalue;
}
}
class Demo{
int div(int a,intb)throws FuShuException {//在功能上通过throws的关键字声明了该功能有可能会出现问题。
if(b<0)
thrownew FuShuException("出现了除数是负数的情况/ by fushu",b);//手动通过throw关键字抛出一个自定义异常。
return a/b;
}
}
class ExceptionDemo2{
public static voidmain(String[] args) {
Demo d = newDemo();
try{
intx = d.div(4,-1);
System.out.println("x="+x);
}
catch(FuShuException e){
System.out.println(e.toString());
System.out.println("出现错误的负数是:"+e.getValue());
}
System.out.println("over");
}
}
异常的转换思想:当出现的异常是调用者处理不了的,就需要将此异常转换为一个调用者可以处理的异常抛出。
13.try catch finally的几种结合方式:
1) try{}catch(){}finally{}
2) try{}catch(){}
3) try{}finally{}
有一种情况,如果出现异常,并不处理,但是资源一定要关闭,所以try finally结合方式只为关闭资源。
细节:finally很有用,主要用于关闭资源。如论是否发生异常,资源都必须进行关闭。当然,有一种情况是finally不执行的:System.exit(0);
当异常出现后,在子父类进行覆盖时,有了一些新的特点:
1) 当子类覆盖父类的方法时,如果父类的方法抛出了异常,那么子类的方法要么不怕抛出异常要么抛出父类异常或者该异常的子类,不能抛出其他异常。
2) 如果父类抛出了多个异常,那么子类在覆盖时只能抛出父类的异常的子集。
注意:
如果父类或者接口中的方法没有抛出过异常,那么子类是不可以抛出异常的,如果子类的覆盖方法中出现了异常,只能try不能throws。
如果这个异常子类无法处理,已经影响了子类方法的具体运算,这时可以在子类方法中,通过throw抛出RuntimeException异常或者其子类,这样子类的方法上是不需要throws声明的。
常见异常:
1) 角标越界异常:IndexOutofBoundsException,包括数组,字符串;
2) 空指针异常:NullPointerException
3) 类型转换异常:ClassCastException
4) 没有这个元素异常:NullPointerException
异常要尽量避免,如果避免不了,需要预先给出处理方式。
需求:
毕老师用电脑上课,开始思考上课中出现的问题。
比如问题是:电脑蓝屏、冒烟。要对问题进行描述,封装成对象。可是当冒烟发生后,出现讲课进度无法继续。出现了讲师的问题:课时计划无法完成。
代码演示:
//定义一个电脑蓝屏异常,让其继承Exception,生成自定义异常
classLanPingException extends Exception{
LanPingException(String message){
super(message);
}
}
classMaoYanException extends Exception{
MaoYanException(String message) {
super(message);
}
}
classNoPlanException extends Exception{
NoPlanException(String message){
super(message);
}
}
class Computer{
private int state =3;
public void run()throwsLanPingException,MaoYanException {
if(state ==2)
throw newLanPingException("蓝屏了");
if(state == 3)
throw newMaoYanException("电脑冒烟了");
System.out.println("电脑运行");
}
public void reset(){
System.out.println("电脑重启");
}
}
class Teacher{
private String name;
private Computer cmpt;
Teacher(String name){
this.name = name;
cmpt = new Computer();
}
public void prelect()throwsNoPlanException{
try{
cmpt.run();
}
catch (LanPingException e){
cmpt.reset();
}
catch (MaoYanException e){
test();//必须写在前面
throw newNoPlanException("课时无法继续"+",因为"+e.getMessage());
}
System.out.println("讲课");
}
public void test(){
System.out.println("练习");
}
}
class ExceptionTest{
public static void main(String[] args) {
Teacher t = new Teacher("毕老师");
try{
t.prelect();
}
catch (NoPlanException e){
System.out.println(e.toString());
System.out.println("换老师或者放假");
}
}
}
值得注意的是:如果需要在程序出现异常之前需要操作调用其他函数,必须将该调用的函数写在抛出异常的前面,否则程序出错。
13,包(package)
1. 定义包
使用package关键字在类的第一条语句定义报名,报名必须全部小写,一般用域名
2. 编译带包的类
javac –d <目录> 源文件名.java
例如:javac –d.Person.java编译到当前目录
3. 默认包
如果一个类没有加上package关键字定义报名,它是在一个默认的包中,以前我们使用的类都没有定义包,默认都在同一个包中,互相直接可以访问;如果两个类定义了包,并且是相同的包,也可以直接访问。
4. 运行带包的类
java 包名.类名(权限定名)
例如:javacn.itcast.PackageDemo
5. 访问权限
private 私有,只有当前类可用,类是不能私有的
默认,同包中的类可用,类默认也是只能同包内使用
protected 保护,通报中的类和子类可用,类不能使用这个修饰符
public 共有,所有的类都可用,如果一个类希望被其他包中的类使用,那么必须被public修饰,public的类必须和文件名同名。
6. 导入其他包中的类
首先要使用的类必须是public修饰的,使用import关键字可以导入其他包中的类:
1) 星号方式导入,导入指定包中所有的类(让指定包中所有的类对本类可见),如果当前包中有同名的类,优先使用当前包中的。
2) 类名方式导入,导入指定包中指定的类,如论当前包中是否有需要的类,都使用导入到包中的类。如果一个类中要是用两个包中的同名的类,那么每次使用的时候都加上包名即可。
7. 有包类和无包类之间的访问问题
无包的类能访问邮宝的类吗? 能,直接导入即可
有包的类能访问无包的类吗? 不能,没有包名无法导入
注意:
1) 写类的时候要加上包名
2) 类要public,并且类名和文件名一致
3) 导入类要写类名
4) 编译用-d,运行带包名
8. 包与包之间访问可以使用的权限有两种:
1) public
2) protected:只能是不同包中的子类可以使用的权限
9. 总结java中的四种权限
范围 public protected default private
同一类中 ok ok ok ok
同一包中 ok ok ok
子类 ok
不同包中 ok
10.导入(import)
为了简化类名的书写,使用一个关键字:import
例如:importpackb.haha.hehe.heihei.DemoC;
如果当前目录下的类特别多,这里可以使用通配符*,即导入子包中所有的类,例如:import packb.haha.hehe.heihei.*;
但是在真实项目开发中,我们为了让程序运行的精简,更快,当我们需要用哪个类的时候,就直接导入哪个类,防止将过多的类导入后,占用空间,导致程序运行过慢。
14,Jar包
1. Java压缩包
1) 方便项目的鞋带;
2) 方便与使用,只要在classpath设置jar路径即可;
3) 数据库驱动,SSH框架等都是以jar包体现的。
2. 如何创建jar包?
格式:jar –cf xx.jar包名,其中,xx代表jar包的名称,前提是需要切换到打包路径中,且路径中已经存在相应包文件,例如:
jar –cfhaha.jar packapack
3. jar命令常见用法:
-c:创建新的归档文档
-f:指定归档文件名
-t:列出归档目录
-v:在标准输出中生成详细输出
当使用jar命令打包程序后,jar包文件中会有一个配置清单文件,设置jar包的classpath路径方式为setclasspath=c:\myclass\haha.jar
将jar包中的详细信息写入硬盘中的文件里:jar –tf a.jar >C:\1.txt
---------------------- ASP.Net+Android+IOS开发、 .Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net