面向对象
面向对象的特征:封装、继承、多态
1.构造函数
给对象进行初始化时,对象一建立就会调用与之对应的构造函数。当分析事物时,该事物具备一些特性或者行为,就将这些内容定义在构造函数中。
u 名称必须与类名一致,不能有返回值类型,没有具体的返回值,通过new调用。
u 系统会默认给该类加入一个空参数的构造函数。
u 可以利用重载的形式定义多个构造函数以对不同对象进行针对性的初始化。
构造代码块:给对象进行初始化,对象一建立就运行,而且优先于构造函数执行。定义的是不同对象共性的初始化内容,而构造函数是给对应的对象初始化。
把共性的初始化内容放在构造代码块中! {共性的内容;}
2.this关键字
代表它所在函数所属对象的引用。简单的说,哪个对象在调用this所在的函数,this就代表哪个对象。
super与this的用法几乎一致,this是本类对象的引用,super是父类对象的引用。
(1)this的用法:当定义类中功能(函数)时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象。但凡本类功能内部使用了本类对象,都用this表示。
class Person{
private String name;
private int age;
Person(int age){
this.age = age;}
//需求:给人定义一个用于比较年龄是否相同的功能。也就是是否是同龄人。
public boolean compare(Person p){
return this.age==p.age; }
}
(2)this语句:用于构造函数之间进行互相调用。
u this语句只能定义在构造函数的第一行!因为初始化要先执行。
u 构造函数第一行,默认有一条隐式语句this()
class Person{
private String name;
private int age;
{
System.out.println("coderun");//构造代码块
}
Person(String name){
this();
this.name =name;}
Person(String name,int age){
this(name);
this.name = name;
this.age = age;}
}
3.static关键字
是一个修饰符,用于修饰成员(成员变量,成员函数),把对象的共享数据存储在单独的空间。当成员被静态修饰后,就有两种调用方式:被对象调用和直接被类名调用。
(1)特点:
u 随着类的加载而加载,随着类的消失而消失。说明它的生命周期最长。
u 优先于的对象存在。明确一点:静态是先存在。对象是后存在的。
u 修饰后被所有对象所共享。
u 可以直接被类名所调用。
(2)注意:
u 主函数是静态的。
u 静态方法中不可以定义this,super关键字。因为静态优先于对象存在。
u 静态方法只能访问静态成员。非静态方法既可以访问静态也可以访问非静态。
(3)什么时候使用静态:
什么时候定义静态变量(类变量)呢?
当对象中出现共享数据时,该数据被静态所修饰存在于方法区,对象中的特有数据要定义成非静态存在于堆内存中。
什么时候定义静态函数呢?
当功能内部没有访问到非静态数据(对象的特有数据),该功能可以定义成静态的。
继承
1.继承
Java只支持单继承,不支持多继承。但支持多层继承,就是一个继承体系。
子父类加载时,类成员的特点:
(1)成员变量
当子类中出现非私有的同名成员变量时,如果子类要访问本类中的变量,用this;要访问父类中的同名变量,用super。
(2)成员函数
当子类出现和父类一模一样的函数时,如果子类对象调用该函数,会运行子类函数的内容,这叫覆盖(或者重写)
u 子类覆盖父类,必须保证子类权限大于等于父类权限,否则编译失败。
u 静态只能覆盖静态。
(3)构造函数
当子类对象进行初始化时,父类的构造函数也会运行,因为子类所有的构造函数第一行默认有一条隐式的语句 super(),它会访问父类中空参数的构造函数。
u 当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。
u 子类的构造函数第一行也可手动指定this语句来访问本类中的构造函数,再通过本类指定的构造函数来访问父类的构造函数
u 子类中至少会有一个构造函数会访问父类中的构造函数。
u 子类构造函数调用父类构造函数用:super(参数) super(name);
u 子类成员函数调用父类成员函数用:super.父类方法 super.show();
2.abstract关键字
抽象。当多个类中出现相同功能定义不同功能主体时,可以进行向上抽取。这时,只抽取功能定义,而不抽取功能主体。
(1)抽象类:
u 抽象方法和抽象类都必须被abstract关键字修饰,抽象方法一定在抽象类中。
u 抽象类不可以用new创建对象。抽象类中的抽象方法要被使用,必须由子类复写全部的抽象方法后才能建立子类对象进行调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。因为该子类继承了抽象类的抽象方法。
u 抽象类只是比一般类多了抽象方法,它可定义非抽象方法,也可不定义抽象方法。
u 需要指出的是,抽象类也是有构造函数的。
(2)abstract关键字不能和哪些关键字共存?
final:被final修饰后,不能被子类继承,无法重写。
private: 私有后,不能被子类继承,无法重写。
static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。
3.final关键字
final作为一个修饰符,可以修饰变量,方法(函数),类
(1)修饰变量:是一个常量只能赋值一次,既可以修饰成员变量,也可以修饰局部变量
(2)修饰方法:不可以被子类重写但是可以重载
(3)修饰类:不能被继承
4.接口
当抽象类中的方法都是抽象方法时,该类可以通过接口的形式来表示。它是对外暴露的规则,是对程序的扩展。用interface定义,用implement实现。
(1)接口定义时,格式特点:
u 接口中常见定义:常量,抽象方法。
u 接口中的成员都有固定修饰符。
常量:publicstatic final
抽象方法:publicabstract
记住:接口中的成员都是public的,以上固定的格式可以省略,java虚拟机默认添加。
(2)接口是不可以创建对象的,因为有抽象方法,需要被子类实现。子类对接口中的抽象方法全都覆盖后,子类才可以实例化。
(3)区分关系:
类与接口之间是实现关系,并且可以多实现
接口与接口之间是继承关系,并且可以是多继承
多态
1.定义
(1)体现:父类引用指向子类对象
Animal a =new Cat();//左边是父类引用,右边是子类对象
(2)必要条件:类之间继承/实现的关系+重写+父类/接口的引用指向子类对象
(3)多态提高了程序的扩展性,但是父类的引用只能访问父类中的成员。可以通过强制转换来访问子类成员:
Animala=new Cat(); //向上转型
Catc=(Cat)a;//向下转型,强制转换
可以看出,多态自始至终都是子类的对象在改变
2.多态中成员的特点:
(1)成员函数:成员函数在多态调用时,编译看左边,运行看右边。
在编译时期:看引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:看对象所属的类中是否有调用的方法。
(2)成员变量和静态成员函数:无论编译还是运行,都看左边(引用型变量所属的类)。
3.instanceof运算符:返回值是boolean类型,判断一个引用指向的对象所属的类是不是某个类或者某个类的子类。左边是一个对象,右边是一个类
用法:对象的引用 instanceof 类名;
4.代码范例:主机接口
思想:先定义一个接口,让需要用到的类实现去这个接口。然后再定义一个类去使用这个接口,此时方法的参数就是接口。那么就可以定义接口的对象来使用重写后的方法。
引申:可以将这两个有相同方法的类A和B进行抽取,再把这个抽取出来的类C当做另一个类D中方法的参数,而这个方法就是完成之前那两个方法。使用时,只需建立D类对象,就可以使用子类重写的方法
interface PCI{ //C
public void open();
public void close();
}
class MainBoard{ //D
public void run(){
System.out.println("mainboard run ");}
public void usePCI(PCI p){//PCI p = new NetCard()//接口型引用指向自己的子类对象。
if(p!=null){
p.open();
p.close(); }
}
class NetCard implements PCI{ //A
public void open(){
System.out.println("netcard open");}
public void close(){
System.out.println("netcard close");
method();}
}
class SoundCard implementsPCI{ //B
public void open(){
System.out.println("SoundCard open");}
public void close(){
System.out.println("SoundCard close");}
}
class MainBoardDemo{
public static void main(String[] args) {
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(newNetCard());
mb.usePCI(new SoundCard());}
}
Object类
Java中所有类的父类。该类定义的是所有对象都具备的功能,因此Object类中的方法可以被重载、重写。
toString():返回该对象的字符串表示
equals() :用于比较对象的引用指向的是否是同一个对象(比较的是地址)
对象比较的两种方法:
hashcode( ) | 根据对象所在的内存返回一个能够唯一代表这个对象的int值。两对象相等,hashcode( )返回值相等;两对象不相等,hashcode( )返回值不相等。 |
equals( ) | 比较的是地址,而不是两个对象是否逻辑相等。 |
通常通过覆盖hashcode( )和equals( )方法类达到比较自定义对象的目的。
public class Student(){
private String name;
private int age;
public student(name,age){
this.name=name;
this.age=age;
}
public bealoon equals(objectobj){
if(!(obj instanceof Student))
return false;
Student s=(Student)obj;
return (name.equals(s.name))&&(age==s.age);
}
public int hashCode(){
final int prime=31;
int result = 1;
result = result * prime + ((name==null)? 0 : name.hashCode());
result = result * prime +age
return result;
}
}
内部类
如果把内部类所在的类称为外部类,那么内部类同时具备类成员和类两个属性。可以分为成员内部类和局部内部类。
l 内部类可以直接访问外部类中的成员,包括private。因为内部类中有一个外部类的引用,格式:外部类名.this 如:外部类名.this.外部类变量/外部类方法
l 外部类要访问内部类,必须建立内部类对象。内部类一般在外部类的内部使用,很少在外部类之外的一个类中使用这个内部类。
1.成员内部类:当内部类定义在外部类的成员位置上
² 一般内部类都默认是非静态成员内部类
² 可以被任何成员修饰符修饰,如private、static、abstract、final。
若内部类被private修饰,就是将内部类在外部类中进行封装,避免了外部其他类使用
若内部类被static修饰(静态内部类),则该内部类就是一个类范畴的属性而不是作为外部类的对象了。此时只能直接访问外部类中的static成员,但可以通过new 外部类( ).成员的方式访问外部非static成员
² 当内部类中定义了静态成员,该内部类必须是static的;当外部类中的静态方法访问内部类时,内部类也必须是static的
² 在外部其他类中,访问内部类,需要创建外部类里面内部类的对象。成员内部类的全限定名是:外部类名.内部类名
直接访问非static内部类的成员时,格式:
Outer out=new Outer();
Inner in =out.new Inner();
//可以简写成
Outer.Inner in = newOuter().new Inner();
in.function();//访问非静态方法
Outer.Inner.staticFunction();//访问静态方法
直接访问static内部类的成员时,格式:
StaticInner in =new Outer.StaticInner();
in.function( );//访问非静态方法
StaticInner.staticFunction();//访问静态方法
2.局部内部类:内部类定义在外部类方法的局部位置上
² 可以直接在外部类方法中创建局部内部类的对象,来调用局部内部类的方法。
² 不能使用访问权限控制符和 static 修饰符;
² 可以直接访问外部类中的成员,但不可以访问外部类方法中局部的变量(和局部内部类等一个层次),除非这个变量被final修饰
class Outer{
int x = 3;
void method(final int a){
final int y = 4;//外部方法中局部的变量,被final修饰
class Inner{
void function(){
System.out.println(y);}}
new Inner().function();
}
}
3.匿名内部类:没有名字的内部类(无构造方法)。是内部类的简写格式,可以简化代码
² 定义匿名内部类的前提:该内部类必须继承一个抽象类或者实现接口。但是不能显式地继承或实现。所以匿名内部类其实就是一个匿名子类对象,而且是带内容的对象。
² 匿名内部类能使用访问权限控制符和 static 修饰符
² 格式:new 父类或者接口(){定义子类的内容}
² 如果多次调用匿名内部类中的方法,可以通过多态创建匿名内部类的对象再调用。
abstract class AbsDemo{
abstract void show();
}
class Outer{
int x = 3;
new AbsDemo(){
int num = 9;
void show(){System.out.println("num==="+num);}
}.show;
//利用多态实现多次调用匿名内部类方法
AbsDemo c=new AbsDemo(){
int num = 9;
void show(){System.out.println("num==="+num);}
}
c.show;
}
异常
Throwable
|--Error:严重的问题,一般不编写针对性的代码对其进行处理
|--Exceptoin:在运行时出现的一些异常,可以使用针对性的处理方式进行处理
|--RuntimeException
异常体系中的所有类以及建立的对象都具备可抛性。可以被throw和throws关键字所操作!
1.Throwable中方法(对捕获到的异常对象进行的常见方法操作)
String getMessage() | 获取异常信息 |
String toString() | 获取异常类名和异常信息 |
void printStackTrace() | 获取异常类名、异常信息以及异常的位置 |
String printStackTrace(PrintStream s) | 将异常内容保存在日志文件中 |
2.异常处理:try-catch-finally语句
try{需要被检测的代码;}
catch(异常类 变量){处理异常的代码;}
finally{一定会执行的语句;(通常是关闭资源代码,因为资源必须被释放!)}
² 有三种方式:try-catch-finally; try-catch; try-finally
² finally代码块只有一种情况不会被执行:在之前执行了System.exit(0) 系统退出
² 一个 try 块后能跟多个 catch 块。多个 catch 块的语法像这样:
3.throws和throw
throws:在方法声明中抛出异常,用在函数上,后面跟异常类名(可多个,用逗号隔开)
throw:在方法代码中抛出异常,用在函数内,后面跟异常对象
注:在函数内部使用throw,要么在内部try-catch处理(没有catch就没有被处理!);要么在函数上声明让调用者处理。(RuntimeException除外)
4.自定义异常:必须是继承Exception或者其子类!
一般通过构造函数定义异常信息,通过throw将自定义异常抛出。
class MyException extendsException{
MyException(String message){
super(message);}}
自定义负数异常
class FuShuException extendsException {
private int value;
FuShuException(String msg){
super(msg);}
}
class Demo{
int div(int a,int b)throwsFuShuException{
if(b<0)
//手动通过throw关键字抛出一个自定义异常对象
throw new FuShuException("出现了除数是负数的情况-",b);
return a/b;}
}
class MyExceptionDemo{
public static void main(String[] args) {
Demo d = new Demo();
try{
int x = d.div(4,-9);
System.out.println("x="+x);
}catch (FuShuException e){
System.out.println(e.toString());}
System.out.println("over");}
}
5. 异常有两种:
编译时异常 | 编译时,如果没有处理(没有throw也没有try),编译失败。该异常被标识,代表这可以被处理 |
运行时异常 | 编译时,不需要处理,编译器不检查。该异常的发生,建议不处理,让程序停止。需要对代码进行修正 |
RuntimeException类:运行时异常。
l RuntimeException以及其子类如果在函数中被throw抛出,可以不用在函数上声明;
l RuntimeException以及其子类如果在函数上被throws声明,可以不通过调用者进行处理。
l 该异常(RuntimeException类及其子类)发生,就是希望程序停止。因为在运行出现了无法继续运算的情况时,只有当停止程序后,才可对代码进行修正。因此自定义异常时:如果该异常的发生,无法在继续进行运算,就让自定义异常继承RuntimeException类。
6.异常在子父类覆盖中的体现:
l 如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了特有的异常,就必须要进行try处理。绝对不能抛!
l 子类在覆盖父类时,如果父类方法抛出异常,那么子类只能抛出父类异常的子类或集合
7.总结:异常的处理原则
l 处理方式有两种:try或者 throws。
l 声明异常时,要声明为具体的异常,以便具体的处理。调用到抛出异常的功能时,声明几个,就处理几个。
l 一个try可对应多个catch。但是最好不要定义多余的catch块,多个catch块中的异常出现继承关系,父类异常的catch块放在最下面。
l catch内,需要定义针对性的处理方式。不要简单地定义e.printStackTrace或者输出语句
l 当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
try{
throw new AException();
}catch (AException e){
throw e;}
如果异常不属于该功能出现的异常,并且处理不了。可以将异常转换后,再抛出和该功能相关的异常。 下左
try{ throw new AException(); }catch (AException e){ throw new BException(); } | try{ throw new AException(); }catch (AException e){ 先对AException处理; throw new BException();} |
如果异常不属于该功能出现的异常,但是可以处理。可将异常产生的和本功能相关的问题提供出去让调用者知道并处理;或将捕获异常处理后,再转换成新的异常抛出。上右
//有一个圆形和长方形,都可以获取面积。对于面积如果出现非法的数值,视为是获取面积出现问题。问题可以通过异常来表示。
class NoValueExceptionextends RuntimeException{
NoValueException(String message){
super(message);}
}
interface Shape{
void getArea();
}
class Rec implements Shape{
private int len,wid;
Rec(int len ,int wid){
if(len<=0 || wid<=0)
throw new NoValueException("出现非法值");
this.len = len;
this.wid = wid;}
public void getArea(){
System.out.println(len*wid);}
}
class Circle implementsShape{
private int radius;
public static final double PI = 3.14;
Circle(int radius){
if(radius<=0)
throw new NoValueException("非法");
this.radius = radius;}
public void getArea(){
System.out.println(radius*radius*PI);}
}
class ExceptionTest{
public static void main(String[] args) {
Rec r = new Rec(3,4);
r.getArea();
Circle c = new Circle(-8);
c.getArea();
System.out.println("over");}
}
包(package)
用来对类文件进行分类管理,给类提供多层命名空间。包名必须是合法的标识符名,写在程序文件的第一行。如果一个源文件不是在default package中,那么此源文件的第一有效行必须是能正确表示源文件所在包的package语句。
包的全限定名:从源代码根目录(src)开始,包名之间有点号隔开。
类的全限定名:类所在的包的全限定名.类名。
u 使用包中的类时都是要使用类的全限定名,包括创建类的对象等。但是使用类的引用则与全限定名没有任何关系。Carcar=new Common.car();
u 包与包之间的访问时:被访问的包中类的权限必须是public;类中的成员权限必须是public或者protected。protected是为其他包中的子类提供的一种权限
u 一个类使用同一个包中的其他类时,可以省略类的全限定名。
u 编译:编译包中的类时,需要进入源代码的根目录,然后根据类源文件的路径和源文件名进行编译,否则编译失败。
1.import语句:
u 两种语法格式:
引入一个类:import 类全限定名;
引入一个包中的所有类:import 包全限定名.*; 不包含子包中的类!
u 一个程序文件中只有一个package,但可以有多个import。
u 用来导入包中的类,而不是导入包中的包。
u Java编译器默认引入java.lang中的所有类。
u 当类中的源码中使用了没有全限定名的其他类,Java编译器寻找这个类的顺序规则:使用第1种格式引入的类;使用与这个类中同一个包中的类和使用第2种引入的类。
2.jar包
Java的压缩包。方便项目的携带和使用,只要在classpath设置jar路径即可
u 数据库驱动,SSH框架等都是以jar包体现的。
u 通过jar.exe工具对jar的操作:
创建jar包 | jar -cvf mypack.jar packa packb |
查看jar包 | jar -tvf mypack.jar [>定向文件] |
解压缩 | jar -xvf mypack.jar |
自定义jar包的清单文件 | jar –cvfm mypack.jar mf.txt packa packb |