类的第二大特点继承:
可以使用extends关键字让一个类继承另外一个类。继承的类为子类(派生类),被继承的类为父类(超类, 基类)。子类会自动继承父类所有的方法和属性。
变量:如果子类中出现非私有的同名成员变量时,子类要访问本类中的成员变量用this,子类要访问父类中的同名变量用super(代表父类对象引用)
1.java中只支持单继承,不允许多继承,
2.但是同一个类可以被多个继承
多个继承一个类简单的说你只有一个爸爸但是你有多个兄弟这就是多个类继承一个类。
3.也可以是b类继承了a类但是c类又继承了b类这样就出现了多层继承。
class a {} class b extends a {} class c extends b {}
多层继承就好比你爸继承你爷爷的基因然后你又继承你爸爸的基因也就间接的让你有了你爷爷的基因。
4.子类继承父类的成员变量和方法但不是继续父类的构造方法,在子类的构造方法中可以用语句super调用父类的构造方法
class Student extends person { public student(String name,int age,String school) { super(name,age); this.school=school; } }
5.如果子类的构造方法中没有显式地调用父类构造方法,也没有使用this关键字调用重载的其他构造方法,则在产生的子类的实例对象时系统默认
调用无参父类的构造方法。也就是说在子类中定义构造方法写不写是一样的
public class b extends a { public b() { super();//这里的意思说就是在满足这个条件写不写这个都一样,没有明确要调用父类的那个构造方法,也没有使用this关键字调用重载的其他构造方法 } }
如果说子类构造方法中没有像是的调用 父类的构造方法,而父类中又没有无参数的构造方法刚会编译错误。
所以我们在定义类型时,只要定义 了有参数的构造方法那么就一定要定义一个无参数的构造方法。
super在子类构造对象时,发现,访问子类构造函数时,父类也运行了。原因是:在子类的构造函数中第一行有一个默认的隐式语句,super();子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。
子类的实例化过程:
对象中成员变量的存储空间初始化的步骤:
1.分配成员变量的存储空间并进行默认的初始化,就是用new关键字产生对象后,对类中的成员变量进行初始化赋值
2.绑定构造方法参数,就是new person(实际参数列表)中所传递进的参数赋值给构造方法中的形式参数变量
3.如有this()调用,则调用 相应的重载构造方法(被调用的重载方法双从第二步开始执行这些流程)被调用的重载构造方法执行完流程后
回到当前构造方法直接跳转到第六步执行
4.显式或隐式追溯调用父类的构造方法(一直到object类为止Object是所有java类的老祖宗)父类的构造方法又从第2步开始对父类执行这些流程,
父类的构造方法的执行流程结束后,回到当前构造方法继续往下执行。
5.进行实例变量的显式初始化操作,也就是执行在定义成员变量时就对其进行赋值操作的语句。
如:
public Student extends person { String school="xue211";//显式初始化 .... }//将这个值赋值给了school
6.执行当前构造方法体中的程序代码
如:
public Student extends person { public Student(String name,int age, String school) { super(name,age);//这里是调用了其他方法而且下面这个是一个普通的赋值 this.school=school; } }
为什么super()和this()调用语句不能同时在一个构造函数中出现?
为什么super()或this()只能作为构造函数中的第一句出现?
super语句必须定义在子类构造函数的第一行,因为父类的初始化动作要先完成。
覆盖父类的方法:
在子类中可以根据需要对从父类中继承来的方法进行改造------方法的覆盖
要求覆盖方法和被覆盖的方法必须要有相同的方法名称、参数列表和返回值类型。
注意:覆盖方法时,不能使用比父类中被覆盖方法更严格的访问权限。
final关键字:
1.java中声明类属性和方法时可以使用关键字final来修饰。
2.final标记的类不能被继承。
3.final标记的方法不能被子类重写。
4.fianl标记的变量(成员变量或局部变量)即成为常量,只能赋值一次。
final int x=3; 这里将x变为了常量x=4;这里对x再进行了赋值也就说是对常量进行再赋值所以会报错
final标记的成员 变量必须在声明的同时或在该类的构造方法中显式赋值,然后才能使用
class test { fianl int x=3; } 或 class test { final int x; test() { x=3; } }
5.方法中定义内部类只能访问该方法内的final类型的局部变量,用final定义局部变量相当于定义了一个常量。它的生命周期超出方法运行的生命周期,
将一个形参定义final也是可以的,这就限定了我们在方法修改形式参数的值。
小知识点:fianl标记的变量就会成为常量。,只能赋值一次但是这个“常量”只能在这个类的内部使用,不能在类的外部直接使用、
当我们用了public static final共同标记常量时这个常量就成了全局的常量而且 这样的定义的常量 只能在定义时赋值,即使在函数里面也不能对其进行赋值
class xxx
{public static final int x=3;....}
抽象类接口:
抽象类:
java中定义一个不含方法体的方法,它的方法体的实现 交给该类的子类根据自己的情况去实现,这样的方法就是抽象方法。包含抽象方法的类就叫抽象类
一个抽象类中可以有一个或多个抽象方法。
抽象方法用abstract关键字来修饰。抽象方法必须用abstract来修饰
抽象类的定义规则:
1.抽象类【和抽象方法】必须用abstract关键字来修饰:
2.抽象类不能被实例化,也就是不能用new关键字去产生对象:因为他是一个模糊的东西无法认清的所以根本无法产生实体。
比如说:有一个人看到罪犯杀人了但是他没看清楚。只是看到人可以认识无法描述出来。这样的一个方法我们就可以说他是一个抽象的
3.抽象方法只需声明。而且不需实现。、
4.含有抽象方法的类必须被声明为抽象类,抽象类的子类必须覆盖所有的抽象方法后才能被实例化,否则这个子类还是一个抽象类、
抽象方法的写法:
1.abstract返回值类型 抽象方法(参数列表);
抽象类和抽象方法的例子
abstract class { abstract int aa(int x, int y) } 注意:含有抽象方法的类肯定是抽象类,抽象类中的某个方法不一定是抽象的
接口(interface):
如果一个抽象类中的所有方法都是抽象的,就可以将这个类用另外一种方式来定义,也就是接口定义。 接口是抽象方法和常量值的定义的集合,
接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现 。
public interface runner { int id=1; void run; }这里定义了一个接口runner访问类型是public,接口里的默认变量是用public static final标识接口中定义的变量就是全局静态常量
我们定义一个新的接口,可以用extends关键字去继承一个已有的接口bn可以定义一个类用implements关键字去实现接口中所有 的方法
还可以去定义一个抽象类,用implements关键字去实现一个接口中定义的部分方法
interface Animal exetends Runner { void breathe(); } class Fish implements Animal { public void run() { System.out.println("fish is swimming"); } public void breathe() { System.out,println("fish is bubbling"); } } abstract LandAnimal implements Animal { public void breathe() { System.out.println("LandAnimal is breathing"); } }
java中设计接口的目的主要是为了让类不受限于单一继承关系而可以继承一些共有的特性从而达到多重继承的目的
多重继承的实现危险性在于一个类可能继承了同一个方法的不同实现,接口讲决不会发生这种 情况,因为接口没有任何的实现
一个类可以在继承一个父类的同时实现一个或多个接口extends关键字必须位于implements关键字之前
class Student extends person implements runner { ... public void run() { System.out.println("the student is running"); } .... }
这里就是将继承放在了implements的前面
接口中定义的常量示例:
class testdemo { fish f=new fish(); int j=0; j=runner.id;//类名.成员的格式 j=f.id//对象名。静态成员 //这两行一个用类的实例对象,一个用接口类 f.id;//出错不能为fianl变量重新赋值,注意这里是前面的代码引用的里面的对象 整个接口的代码是贯通的 }
接口的实现和特点:
1.实现 一个接口就是要实现 该接口的所有方法(抽象类除外)
2.接口中的方法都是抽象的
3.多个无关的类可以实现同一个接口,一个类可以实现多个无关的接口从来可以说用接口体现了多继承。
对象的多态性:
对象的类型转换:
基本数据类型变量的类型转换其实和对象类型转换也差不多是一个道理
1.子类转换成父类
这个是自动完成转换动作的只要子类创建一个实例对象那么子类也就能够自动转换成父类类型。
因为编译器能够自动 将子类的实例对象赋值给父类的引用变量也就有了子类自动转换成父类类型。
简单的来说:人是男人女人的老祖宗,所以人就是父类 男人和女人分别是两个子类。我们 可以说男人是人吧但是不可以说人是男人吧
因为不是每个人都是男人 但是第个男人都是人 所以我们就可以将子类实例后赋值给父类的引用类型变量然后也就可以自动成为父类了
2.父类转换成子类
这里首先我们要确定父类的类型。比如人的不说我们首先要判断父类是男人还是女人然后是什么人的时候进行父类与之类之间转换。
然后当是我们需要转换的人的时候那么就进行强制的转换
3.instanceof操作符(这也可以说是一个比较运算符)
可以用instanceof判断是不回一个类实现了某一个接口,也可以用它来判断一个实例对象是否属于一个类。格式如下
对象 instanceof 类(或接口) 主要是检测是否是类的对象
它的返回值是boolean 或true 或false
public static void CallA(A a) { if(a instanceof B) { B b=(B)a; b.func1(); b.func2(); b.func3(); } else { a.func1(); a.func2(); } }//这样写的目的就是加了一个判断进去主要是为了父类转换成子类,也就这样说吧这里主要是加一个判断进去将人转换成男人也就是父类转换成子类所以的来说我们也就要判断一下他是否是男人如果是那么我们就进行一个强制的父类转换成子类。如果不是那么就不换
object类:
object类是所有类的父类。如果一个类没有使用extends关键字明确标识继承另一个类,那么这个类就默认object类,因此object类是所有类的最高层。
java中的任何一个类都是他的子类,由于object衍生出了所有类,所以object方法适用于所有类
public class person { ... } /和下面这个是一样的因为他们其实都是object的子类,只是平时省略了object不写 public class person extends Object { ... }
Object中有一个方法quals方法比较两个对象是否相等,默认值是false因为类的继承特性所 以这个方法可以在任何类中使用,便返回值总 是false,
比较结果就不一定此自定义类中必须覆盖Object类中的equals方法
示例就是这东西了(借鉴)
class Student { String name; int age; boolean equals(Object obj) { Student st=null; if(obj instanceof Student) st=(Student)obj; else return false; if(st.name==this.name&&st.age==this.age) return false; } public static void main(String[] args) { Student p=new student(); Student q=new Student(); p.name="xyz"; p.age=18; q.name="xyz"; p.age=18; if(p.equals(q)) System.out.printlln("p与q相等"); else System.out.println("p与q不等"); } }
面向对象的多态性:
执行同一个函数以多种的形态展现在大家的面前这就是面向对象的多态性。
多态的特点:
1.应用程序不必以每个子灶编写功能调用,只需要对抽象基类进行处理即可。可提高 程序的可复用性。
2.子类的功能可以被基类的方法或引用变量调用,这叫向后兼容,可以提高程序的可扩充性,可维护性。
其实最好的例子就是台式电脑。他的主机箱里面的东西。是可以更换的,比如说那个什么网卡啊CPU啊什么的
1.多态的体现
父类的引用指向了自己的子类对象,即父类的引用也可以接受自己的子类对象。
2.多态的前提
必须是类与类之间有关系,要么继承,要么实现 必须存在覆盖
3.多态的好处
多态的出现大大的提高了可扩展性
4.多太的弊端
提高了扩展性但是只能使用父类引用访问父类成员
5.多态的应用
Animal a=new Cat();类型提升,把猫向上转型,由jvm自动转型。和基本类型同理。
这时如果要调用子类猫中的成员的话,就得强制转换了Cat c=(Cat)a向下转型。
千万不要出现:将父类对象转成子类类型。Animal a=new Animal();而能转换的是父类的引用指向了自己子类对象时才可以被提升类型,也可以被强制转换
在多态中(非静态) 成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有编译通过,如果没有编译失败、
在运行时期:参阅对象所属的类中是否有调用的方法。
总结:成员函数在多态调用时,编译看左边,运行看右边。
在多态中成员变量的特点
无论编译和运行,都参考左边(引用类型变量所属的类),也就是说创建一个父类引用指向子类对象,而父类和子类中有同名的变量的话,这时用这个引用调用变量,结果是调用的父类的变量。
在多态中静态成员函数的特点
无论编译和运行,都参考左边,就是看是谁的引用就调用谁的函数或变量
匿名内部类:
1.匿名内部类其实就是内部类的简写格式。
2.定义匿名内部类的前提: 内部类必须是继承一个类或者实现接口。
3. 匿名内部类的格式: new 父类或接口(){定义子类的内容}。要调用子类的成员
4.其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。
也可以理解为带内容的对象。
abstract class A { abstract public void fun1(); } class outer { public static void main(String[] args) { new Outer().callInner(new A() {public void fun1() { System.out.println("implement for fun1"); } });//这里面的内容从new后面的{}里面的内容就是一个匿名内部类也是他的格式 } public void callInnwe(A a) { a.fun1(); } }
异常:
异常嘛:用最简单的一句话来说就是程序运行不正常。java很犀利他会把你异常的原因位置给我们返回来
try.. catch语句:
try
{
需要被检测的代码
}
catch(异常类 变量)
{
处理异常代码:(处理方式);
}
finaly
{
一定会被执行代码
}
对于问题的划分:1,一种是严重的问题,2,一种是非严重的问题。
对于严重的,java通过Error类进行描述。
对于Error一般不编写针对性的代码对其处理。
对于非严重的,java通过Exception类进行描述
对于Exception可以使用针对性的处理方式进行处理。
因为Error和Exception都具有一些共性内容,如不正常情况信息引发原因等
所以他们都是Throwable的子类
这里是在知道异常 情况下处理异常try catch这个是用来捕捉异常并处理的
throws 关键字:
在功能上通过throws的关键字声明了该功能有可能出现问题。
把有可能出现 异常的语句问题抛给调用者,并且让调用者必须处理该异常,否则编译出错 也可以将所有异常都抛出去
throws这个关键字很好的弥补了try...catch的不足因为他可以处理一些有可能发生的问题及异常类别
但是在调用者调用该方法时就必须用try...catch了否则会出现报错
如果一个方法中的语句执行时可能生成某种异常,但不知道如何处理,那么则此方法声明抛出异常,表明该方法将不对这些异常进行处理
这个抛出就这样说吧! 假设一个问题可能 出现异常我们就将这个异常抛给上级处理如果上级处理不了他再上报给他的上级。然后到了最顶端这个问题还是处理不了
那么我们就把这个问题丢掉洋处理了。就可以说是这里抛出异常抛出的就是处理不了的异常
自定义异常与throw关键字:
Exception类是java.lang.Throwable类的子类,Exception类继承了Throwable类的所有方法,其实使用Exception的子类来描述任何特定的异常的,Exception是所有异常的父类
如:ArithmeticException 在算术运算中发生的异常,NullPointerException变量还没有指向一个对象就引用这个对象的成员
ArrayIndexException访问数组对象中不存在元素。
当然除了系统给我们的这个子类外我们也可以自己定义异常类但是必须继承Exception类
java上通过throw抛出异常对象 格式 throw 异常对象
在一个方法内使用throw抛出异常对象,如果该方法内部没有用try...catch语句对这个抛出的异常进行处理,则此方法应声明抛出异常,而由该方法的调用者处理
如果要在devide函数接收到第二个除数为负数时,向调用者抛出自定义DevideByMinusExcepton对象
class test { punlic int devide(int x,int y) throws ArithmetException,DevideByMinnusException//定义异常对象
{ if(y<0) throw new DevideByMinusException("被除数为负",y);//这里抛出的异常对象就是调用者在catch(Exception e){}语句中接收的变量e int result=x/y; return x/y; } }
我们也可以在一个方法中使用throw try...catch语句来实现程序的跳转
void fun() { try { if(x==0) thrownew YyyException("Yyy");//跳转到代码块1处 else(x==1) throw new XxxException("Xxx");//跳转到代码块2处 } catch(Exception e) { 代码块1 } catch(XxxException e) { 代码块2 } }
finally关键字:
在try...catch后面还有一个finally语句,finally语句中的代码块不管是否异常都会执行的
finally的特殊之处即使try代码块和catch代码块中使用了return语句退出 当前方法或break跳出某个循环便是finally语句后面的代码块还是要执行的
finally中代码块唯一不能被执行的唯一情况是:在被保护代码块中执行了System.exit(0)。
每个try语句都必须有一个或多个catch语句对应,try代码块与catch代码块及finally代码块之间不能有其他语句、
try{....} int x=3+5;//这样是非法的是 catch(Exception e){...}
异常使用的一些细节:
1.一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或异常子类
2.如果父类抛出异常,那么覆盖方法必须抛出那些京戏忐忑的一个子集,也就是说不能抛出新的异常
包:
java通过引入包(package)机制,提供类的多层命名空间
package语句:
package org.it315; public class Testpackage { public static void main(String[] args) { new Test().print(); } } class Test { public void print() { System.out.println("the program is demostrating how tousing package!"); } }//这里指示源文件中所有类都位于包org.it315中,位于包中的每个类的完整名称都应该是包名与类名的组合比如上面的类testpackage的完整名称是org.it312.testpackage同一个包中的类相互访问不需要指定包名。就好比一个北京人说我要去一趟上海和一个外国人说我要去一趟中国上海
如果说两具类的完整名称不一定相同但是其类名却相同却是两个不同的类,应存放在不同的目录结构中
同一个包中的类不必生关位于同样的目录,只要通过classpath分别指向这两个位置就可 以了
package语句作为java源文件的第一条语句,指明文件中定义的类所在的包,必须把包声明放在源文件的最前面,第个源文件只能声明一个包。
如果说没有package那么则为默认无名包。但是在实际开发中没有使用无名包的类
import语句及应用:
包与包之间的访问,被访问的包中的类以及类中的成员,需要public修饰。
不同包中的子类还可以直接访问父类中被protected全线修饰的成员。
public protected 默认 private
同一个类中 ok ok ok ok
同一个包中 ok ok ok no
不同包的子类 ok ok no no
不同包 ok no no no
找不到某个类可以有三种情况:
1.文件名写错了。
2.没有import类所在的包名
3.classpath设置错误
import在程序中必须写在第一行
import org.it315.example.*;这里是导入了包中的所有类
import org.it315.example.Test;第二个import语句只导入了该包中的Test类,那么包中的其他类就不起作用,在程序中Test我们不用写包名,但是对于该包中的其他类,我们还必须要加上完整的包名
父类与之类之间能众语音上看出他们很亲近,org.it315.*,org.it315.mail.*,从包名就可以看出他们的组织。但是父包和子包在使用上没有任何关系,如父包中的类调用子包中的类,必须引用 子包的全名,不能省略父包名部分。另外当import了一个包中所有类,并不会import这个包的子包中的类,如果程序中用到了子包的类需要再次对子包作单独引入,就好比在程序中经常看到
import java.awt.*;
import java.awt.event.*;
JDK中的常用包
sun公司在jdk中为我们提供了大师的各种实用类,通常称之为API(ApplicastionProgrammingInterface)这些按功能不同分别被放在不同的包中,供我们使用
1.java.lang|___包含如String、 Math、 Integer、 System 、和Thread提供常用功能
2.java。awt____包含了构成了抽象窗口工具集(abstract window toolkits)的多个类这些类被用来构建和管理应用程序的图形用户界面(GUI)
3.java.applet——包含applet运行所需的一些类
4.java.net ——包含执行与网络相关的操作的类
5.java.io——包含能提供多种输入/输出的功能类
6.java.util——包含一些实用工具类,如定义系统软件特性,使用与日期日历相关的函数
注意的是 在java1.2以后的中,java.lang这个包会自动被导入,对于其中的类。不需要使用import语句来做导入了,如我们前面经常使用的System类
访问控制:
访问控制修饰符一共有四个 public protected default private
类成员的访问控制:
1.private访问控制
不能在方法体内声明的变量前加private修饰符、
2.默认访问控制
如果一个成员方法或成员变量名前没加任何 访问控制符,我们就叫这个成员是默认的(default)或友元(friendly) 或包类型的(package)默认访问控制成员可以被这个包中的其他类访问,如果一个子类与父类位于不同的包中,子类也不能访问父类中的默认访问控制成员
3.protected访问控制
如果 一个成员方法 或变量名前使用了protected访问控制符,那么这个成员即可以被同一个包中的其他类访问,也可以被不同包中的子类访问
4.public访问控制
如果一个成员成员变量前使用了public访问控制符,那么这个成员可以被所有的类访问,不管访问类与被访问类是否在同一个包中。
private defalut protected public
同一个类 ok ok ok ok
同一个包中的类 ok ok ok
子类 ok ok
其他包中的类 ok
这就是一个控制符权限制表
类的访问控制:
除了类的成员有访问控制外,类本身也有访问控制,即在定义类的class关键字前加上访问控制符,但是类的本身只能有两种 访问控制,public和默认。
父类不能是private和protected否则子类无法继承public能被所有的类访问,默认修饰符(也就是在class前不加任何关键字)的类只能被同一个包中的所有类访问
小知识点:
只要在class前没有使用public修饰符,源文件的名称可以是一切合法的名称,带public修饰符的类名必须与源文件名相同,
一个.java的源文件中可以包含多个public类么
不可以》因为因为要保存文件,而文件名就是这个public类
java的命名习惯:
1.包名中的字母一律小写,
2.类名,接口名应该当使用名词。每个单词首字母大写
3.方法名 第一个单词小写,后面每个单词首字母大写
4.变量名,第一个单词小写,后面每个单词首字母大写
5.常量名中的每个字母一律大写。
使用jar文件:
我们用jdk中的包与类主要在jdk的安装目录的jre\lib\rt.jar文件中,由于虚拟机会自动国找到这个jar包,所以我们在使用这个jar包的类时不需要再用classpath来指向他们的位置了
jar文件包:
jar__java Archive File jar文件就是一种说压缩文件,与我们觉的zip压缩文件格式兼容,习惯上换为jar包
当需要把一些类提供给别人使用时我们就将这些类压缩到一个jar文件,以jar包的方式提供给别人使用,只要别人把的classpath环境变量的设置中包含这个jar文件那么jvm就能自动在内存中解压这个jar文件把这个jar文件当作一个目录,在这个jar文件中去寻找需要的类及包名所对应的目录结构。
了解了jar文件之间的内部结构后我们就可以通过 设置classpath环境变量指向一个具体的jar文件
在设置classpath时不能使用相对路径
jar命令详解:
jar命令是随jdk自动安装的,存放在jdk安装目录下的bin目录中,windows中文件名为jar.exe
1.jar cf test.jar test
该命令没有执行过程显示,执行结果是当前目录生成了test.jar文件如果当前目录已经存在那么该文件将覆盖
2.jar cvf test.jar test
该命令与上例中的结果相同,,便是由于v参数的作用,显示出了打包过程的详细信息
3.jar test.jar
该命令显示出jar文件中包含的所有目录和文件名列表,
4.jar tvf test.jar
该 命令除了显示目录和文件名外,还显示了各目录和文件的大小 ,创建时间等信息
5.jar xf test.jar
解压test.jar到当前目录,不显示任何信息。
6.jar xvf test.jar
解压到当前目录,显示出解压过程的详细信息
7.使用重定向
利用tvf参数可以查看jar文件的内容。要是jar文件很大,包含很多,这时可能会因为显示 过多的信息屏幕刷新速度过快,而不能正常浏览
所以我们只需要执行jar tvf rt.txtx>c:\rt.txt后面是重定向存储的文件目录,这里也就是将这些内容重定向到这个文件中我们只需要去这个文件去查看就可以了
使用winrar 对jar文件进行查看:
不用jar自带的解压功能进行解压而用winrar来进行jar文件的解压不仅方便民快速而且还便于我们轻松的浏览jar文件中任意目录,并且层次清晰。
注意:
1压缩后的jar文件中的目录结构
2.快速查看jar包中是不回有要找的类