3.9抽象类
1、特点
⑴、被abstract修饰的,只有声明没有实现的方法就是抽象方法,抽象方法必须被定义在抽象类中,该类也得被abstract修饰。
⑵、抽象类不可以实例化,因为调用方法没有意义。
⑶、抽象类的子类必须覆盖其所有的抽象方法后,该子类才可以实例化,否则该类还是抽象类。
2、问题细节
⑴、抽象类中有构造方法,用于给子类对象进行初始化
⑵、抽象类中也有非抽象方法,目的就是不让该类创建对象
3、抽象类不可以与那些关键字共存?
⑴、private:如果私有了,就不可以被子类覆盖了
⑵、static:
⑶、final:final是最终的,被他修饰的不可以覆盖。
4、抽象类与一般类的异同点:
⑴、相同:他们都是用来描述事物的,都在内部定义成员
⑵、不同:①、一般类有足够的信息描述事物,而抽象类信息不足
②、抽象类可定义抽象方法和非抽象方法,而一般类只能定义非抽象方法
③、抽象类不可以实例化,而一般类可以。
5、抽象类一定是父类,因为需要子类覆盖其所有的抽象方法后,才能对子类实例化。
abstractclass Employee {
privateString name;
privateString id;
privatedoublepay;
Employee(String name, String id, double pay) {
this.name = name;
this.id = id;
this.pay = pay;
}
publicabstractvoidwork();
}
class Manager extends Employee{
privateintbonus;
Manager(String name, String id, double pay, int bonus) {
super(name,id,pay);
this.bonus = bonus;
}
@Override
publicvoid work() {
Sop("Manager work");
}
}
class Pro extends Employee{
Pro(String name, String id, double pay) {
super(name,id,pay);
}
@Override
publicvoid work() {
Sop("Pro work");
}
}
publicclass AboutAbstract {
publicstaticvoidmain(String[] args) {
Manager man = new Manager("hufei", "4556",11110, 256);
man.work();
}
}
3.10接口
1、接口中常见的成员:全局常量和抽象方法
注意:接口中的成员都是公共的,修饰符都是可以省略,但不建议,因为那样阅读性差。
2、实现:类与接口之间的关系(implements)
接口是不可实例化的,只能由子类覆盖接口中的所有抽象方法后,子类才可以实例化
3、多实现
⑴、出现的原因:java中不支持多继承,于是改良成多实现,接口的出现避免了单继承的局限性
⑵、一个类中可以实现多个接口,因为接口中都是抽象方法,都没有方法体
⑶、实现与实现之间的关系:可以多继承,因为接口中都是抽象方法,都没有方法体。
⑷、一个类在继承另一个类的同时,还可以实现多个接口
4、特点:
⑴、接口是对外暴露的规则
⑵、接口是程序的功能扩展
⑶)、接口的出现降低了耦合性(紧密联系程度)
⑷、接口可以用来多实现
5、接口与抽象类的异同点
⑴、相同点:都是不断向上抽取而来的
⑵、不同点:①、前者需要被实现,而且可以多实现;后者需要被继承,但只能当单继承。
②、前者只能定义抽象方法,必须由子类去实现;后者可以定义抽象与非抽象类方法,子类继承后,可以直接使用非抽象方法。
③、前者在定义体系外的功能扩展;后者可以定义体系的基本共性内容
6、代码示例
abstractclass Student{
abstractvoidstudy();
void sleep(){
Sop("sleep");
}
}
interface Smoke{
publicabstractvoid smoking();
}
class Zhangsan extends Student implements Smoke{
publicvoidsmoking() {}//实现抽烟接口
@Override
voidstudy() {}//复写study方法;
}
publicclass AboutInterface {
publicstaticvoid main(String[] args) {
Zhangsan zs = new Zhangsan();
zs.sleep();
}
}
3.11 多态
1、多态的体现:父类的引用指向了自己的子类对象,
2、好处:大大提高程序的扩展性
3、前提:必须有关系:继承,接口.必须存在覆盖
4、弊端:虽提高了扩展性,但是只能使用父类的引用访问父类中的成员
5、多态的应用
6、多态时,成员的特点
⑴、成员方法:在编译时,参阅引用型变量中所属的类中的是否存在能调用的方法,有,编译通过,否则,失败。在运行时,参阅对象所属的类中是否有调用的方法
简单总结:成员方法在多态调用时,编译看左边,运行看右边
以下注意面试题
⑵、成员变量:无论编译,还是运行都参考引用型变量中所属的类中的是否有调用的成员变量,有,编译通过,否则,失败。即左边
⑶、静态方法:无论编译,还是运行都参考左边,从某种意义上讲,不涉及多态。
7、代码示例
abstractclass Animal{
abstractvoid eat();
}
class Cat extends Animal{
void catchMouse(){
Sop("抓老鼠");
}
voideat() {
Sop("吃鱼");
}
}
class Dog extends Animal{
voidwatchHome(){
Sop("看家");
}
voideat() {
Sop("吃骨头");
}
}
class Pig extends Animal{
voidwatchHome(){
Sop("看家");
}
voideat() {
Sop("饲料");
}
}
publicclass AboutPolymorphic {
publicstaticvoidmain(String[] args) {
/* Cat c = new Cat();
c.eat();
Dog d = new Dog();
d.eat();
Pig p = new Pig();
//为了提高以上代码的复用性,于是将eat功能提取出来写成function方法
function(c);
function(d);
function(p);
//可是当我们要扩展功能,比如加个pig,这样的话有得写function功能,可是function方法都一样,为了提高代码的复用性
*/
//一个事物的多种存在形态
// Animal a = new Cat(); //类型提升,向上转型
// c.eat();
// Cat c = (Cat)a;
//如果想要调用猫的特有方法,强制将父类的引用,转换成子类类型,即向下转型
/*注意:①千万不要出现这样的操作,就是将父类对象转换子类类型。
②我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。
③多态自始至终都是子类对象在做着变化
*/
//c.catchMouse();
function(new Cat());
function(new Dog());
function(new Pig());
}
publicstaticvoidfunction(Animal a){
a.eat();
if(a instanceof Cat){
//类型判断:instanceof
//作用:用于判断对象的具体类型,只能用于引用数据类型判断,以及在向下转型前用于健壮性的判断。
Catc = (Cat)a;
c.catchMouse();
}elseif(a instanceof Dog){
Dogd = (Dog)a;
d.watchHome();
}
}
/*public static void function(Cat c){
c.eat();
}
public static void function(Dog d){
d.eat();
}
public static void function(Pig p){
p.eat();
}*/
}
3.12 内部类
1、访问规则
⑴、内部类可以直接访问外部类中的成员,包括私有。之所以可以直接访问外部类的成员,是因为内部类中持有了一个外部类的引用,其格式是外部类名.this,
⑵、外部类要访问内部类,必须建立内部类对象
2、直接访问内部类格式
⑴、当内部类在外部类的成员位置上,而且非私有,在外部其他类中,可以直接建立内部类对象,其格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象;
Outer.Inner in = new Outer().new Inner();
⑵、当内部类在成员位置上,就可以被成员修饰符修饰
①、private :将内部类在外部类中进行封装
②、static:内部类就具备static的特性,称之为静态内部类。当内部类被static修饰后,只能直接访问外部类中的static成员,出现访问局限
a、在外部其他类中,如何直接访问static内部类的非静态成员?
new Outer.Inner().function();
b、在外部其他类中,如何直接访问static内部类的静态成员?
Outer.Inner.function();
c、当内部类中定义了静态成员,内部类必须是静态的
d、当外部类中的静态方法访问内部类时,内部类也必须是静态的
3、内部类定义原则
当描述事物时,事物的内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容。
4、局部内部类
⑴、不可以被成员修饰符修饰
⑵、可以直接访问外部类中的成员,因为还持有外部类中的引用,但是不可以访问它所在的局部中的变量,只能访问被final修饰的局部变量。
5、匿名内部类
⑴、前提:内部类必须继承或实现一个外部类接口
⑵、格式:new 父类或者接口(){定义子类的内容}
⑶、其实匿名内部类就是一个匿名子类对象,可以理解为带内容对象
⑷、局限性:当匿名内部类中方法过多的话,会造成混乱,因此其中定义的方法最好不要超过3个。
⑸、应用:当方法参数时接口类型时,而且接口中只有不超过3个,可以用匿名内部类作为实际参数进行传递
6、代码示例:
abstractclass AbsDemo{
abstractvoid show();
}
class Outer{
privatestaticintnum =4;
/*匿名内部类
class Inner2 extends AbsDemo{
@Override
void show() {
Sop(num);
}
}
public void function(){
new Inner2.show();}
-------------------------------------------------------------------------
以上的代码可以写成以下形式
public void function(){
new AbsDemo(){//new AbsDemo(){void show() Sop("num"+num);}是AbsDemo类的子类对象,因为只有子类才能复写父类AbsDemo的抽象方法,当方法有几个的时候,可以给其去个名字AbsDemo a = newAbsDemo();
@Override
void show() {
Sop("num"+num);
}.show();
}*/
class Inner{//当类是内部类时,就变成了外部类的成员了,所以可以被private修饰。
//static class Inner{加静态的情况
void function(){//非静态的情况
//static void function(){加静态的情况
int num = 6;
Sop("innner:"+/*Outer.this.*/num);
//内部类可以直接访问外部类中的成员
}
}
voidmethod(){
finalint x= 56;
class PartInner{ //局部内部类
void function(){
Sop(Outer.this.num);
}}
new PartInner().function();
/*Inner in = new Inner();//外部类要访问内部类,必须建立内部类对象
in.function();*/
}
}
publicclass InnerClass {
publicstaticvoidmain(String[] args){
//new Outer.Inner().function();访问static内部类的非静态成员的方式
//Outer.Inner.function();访问static内部类的静态成员的方式
Outer out = new Outer();
out.method();
//直接访问内部类中的成员
Outer.Inner in = new Outer().new Inner();
}
}
目标四:2013/10/14 6:27
目标五(复习前面所有内容):2013/10/15 7:24
3.13 模板方法模式
1、原理:在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定部分,那么这时就将不确定的部分暴露出去,由该类子类去完成。
2、例题:
(1)、需求:获取某一段程序运行的时间。
(2)、原理:获取程序开始和结束的时间并相减即可。
(3)、代码示例:
abstractclass GetTime{//确定的代码依然放在这个方法中,只有不确定的runCode被覆写
publicfinalvoidgetTime(){//利用final防止复写getTime方法
long start = System.currentTimeMillis();//获取当前时间
runCode();
long end = System.currentTimeMillis();
Sop("毫秒"+(end-start));
}
publicabstractvoidrunCode();//方法体不确定,所以抽象
}
class SubTime extends GetTime{
@Override
publicvoid runCode() {//由于for循环代码在本例中i的值不确定,所以将其复写
for (int i = 0; i < 1000; i++) {
Sop(i);
} } }
publicclass TemplateMethodPattern {
publicstaticvoidmain(String[] args) {
SubTime gt = new SubTime();
gt.getTime();
//Sop("毫秒"+gt);
}}
3.14 包
3.14.1Java中常用的包
1、java.lang:包含一些Java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能。
2、java.awt:包含了构成抽象窗口工具集(abstract windowtoolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。
3、java.net:包含执行与网络相关的操作的类。
4、java.io:包含能提供多种输入/输出功能的类。
5、java.util:包含一些实用工具类,如定义系统特性、使用与日期日历相关的方法。
3.14.2定义带包类
1、使用package语句加上包名来定义类所属于的包,包名全部小写
2、package语句为Java源文件的第一条语句
3、如果一个类中没有使用package语句,这个类为缺省无包名
4、一个类如果想被其他包中的类引用,必须使用public关键字修饰。构造方法也需要public,如果一个类被声明为public,那么必须和文件名同名
3.14.3使用带包的类
1、在使用带包的类时需要使用全限定名(包名.类名)
全限定名有绝对路径的意思,比如一个文件file的存放路径,其绝对路径可能是/usr/local/sbin/file;这个名词也用在其他地方,比如Java类包的定名:com. linux.struct.sort.bubblesort,从最原始最上层的地方援引到具体的对象,这就是全限定名了。
2、在每次写类名时都使用全限定名很麻烦,我们可以使用import导入包,之后再使用就无需写包名了星号*:导入一个包中所有类。优先匹配当前包中的类,如果当前包没有再匹配导入包中的类,具体类名:导入指定一个类。无论当前包中是否有同名类,都直接匹配导入的类。
3、无包的类可以使用有包的类,有包的类不能使用无包的类。
3.14.4编译运行带包的类
1、编译一个带包的源文件,在生成class文件的同时需要生成包文件
编译命令:javac –d <目录> 源文件名.java
2、运行有包的类时需要加上包名
运行命令:java 包名.类名
3.15 jar文件
3.15.1什么是jar文件
1、jar文件是Java文件的一种压缩格式
2、一般来讲,我们会将一个软件系统的所有class文件打成一个jar文件以供别人使用
3、当我们用到jar包中的类时,需要将jar文件的绝对路径加到classpath当中
3.15.2如何压缩jar文件
1、将编译好的带包的class文件压缩成一个jar文件称为打jar
2、打jar命令:jar cvf jar包名.jar 要打包的文件/文件夹
3、运行jar文件命令: java -jar jar文件名.jar
3.16访问控制符
1、类的访问控制符有两种
⑴、public关键字修饰:可以被所有的类访问
⑵、缺省为default:只能被同一包中的类访问
2、成员变量和方法访问控制符:
下面哪一种修饰词能使一个类中的成员变量仅仅具有包可见性:
A、protected
B、public
C、private
D、以上皆不对
3.17代码编写规范
1、标识符命名规则(驼峰式)
⑴、类名首字母大写:XxxYyyZzz
⑵、变量名、方法名首字母小写:xxxYyyZzz
⑶、包名全小写:xxx.yyy.zzz
⑷、常量名全大写:XXX_YYY_ZZZ
2、大括号的位置
⑴、大括号应成对出现,第一个大括号应在第一行语句后面
⑵、方法后面紧跟大括号,没有空格
⑶、关键字(while、for、if)后面应留一个空格
3、赋值语句之间用分号分隔,分号后面应空一格
4、代码折行应按照代码等级对齐,运算符写在下一行