面向对象:基于面向对象思想,强调的是对象(实体)。
特点:
1.面向对象就是一种常见的思想,符合人们的思考习惯;
2.面向对象的出现,将复杂问题简单化;
3.面向对象的出现,让曾将在过程中的执行者,变成了对象中的指挥者。
类:
用java语言对现实生活中的事物进行描述,通过类的形式来体现的。
怎么描述呢?
对于事物的描述只关注两方面:属性和行为。
对象:其实就是该类事物实实在在存在的个体。通过new来创建。
类与事物之间的关系?
类:事物的描述。
对象:该类事物的实例。
定义类就是定义类中的成员。
成员:成员变量-->>属性
成员函数-->>行为
成员变量和局部变量的区别:
1.成员变量:定义在类中,整个类都可以访问;
局部变量:定义在函数中,语句中,局部代码块中,只在所属区域内有效。
2.成员变量定义在堆内存的对象中,局部变量定义在栈内存的方法中。
3.成员变量随着对象的创建而存在,随着对象的消失而消失。
局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。
4.成员变量有默认的初始化值,局部变量没有默认的初始化值。
匿名对象:
1.当对象对方法只调用一次时,就可以简化成匿名对象;
2.可以作为实际参数进行传递。
this:当成员变量和局部变量重名时,可以用this区分,this代表对象,代表当前对象
this就是所在函数所属对象的引用,代表本类对象的引用
1.那个对象调用了this所在的函数,this就代表那个对象,被对象调用都有一个this引用
2.this也可以在构造函数中调用其他构造函数,只能定义在构造函数的第一行,因为初始化动作要先执行。
super:代表一个父类的空间
static:被它修饰的数据称为共享数据
特点:
1.static是一个修饰符,用于修饰成员
2.static修饰的成员被所有对象所共享
3.static优先于对象存在,因为static的成员随着类的加载已经存在了
4.stitic修饰的成员可用类名调用
5.static修饰的数据是共享数据,对象存储的数据是特有的数据。
静态使用的注意事项:
1.静态方法只能访问静态成员(非静态既可以访问静态也可以访问非静态)
2.静态方法中不能使用this或者super
3.主函数是静态的
对象是用来封装特有数据的
静态代码块:
随着类的加载而执行,而且只执行一次。
作用:用于初始化类
构造代码块:可以给所有对象初始化,只要创建对象就运行。
构造代码块优先于构造函数执行,构造函数是给对应的对象进行针对性的初始化
在子类构造函数时,访问子类构造函数发现父类也运行?
原因:在子类的构造函数中第一行有有一个默认的隐式语句super();
super()就是调用父类中空参数的构造函数
子类的实例化过程:
子类中所有的构造函数都会默认访问父类中空参数的构造函数。
如果父类中没有空参数构造函数,子类的构造函数就必须用super明确调用父类中哪个构造函数。
注意:super语句必须定义在子类构造函数的第一行,因为父类的初始化动作必须先完成。
同时如果子类构造函数使用了this调用了本类的构造函数时,那么super就没有用。
因为super和this都只能定义在第一行。所以只能有一个,但可以保证的是子类中肯定会有其他的构造函数访问父类的构造函数。
一个对象的实例化过程:视频10.18也有
Person p=new Person();
1.JVM会读取指定路径下的Person.class文件,并加载进内存,并会先加载Person的父类(如果有直接父类的情况下);
2.在堆内存中开辟空间,分配地址;
3.并在对象空间中,对对象的属性进行默认初始化;
4.调用对应的构造函数进行初试化;
5.在构造函数中,第一行会先到调用父类中的构造函数进行初始化;
6.父类初始化完毕后,再对子类的属性进行显示初始化;
7.构造代码块初始化
7.再进行子类构造函数的特定初始化;
8.初始化完毕后将地址赋值给引用变量。
对象初始化demo1:
class Fu
{
Fu()
{
show();
}
void show(){
System.out.println("fu show run...");
}
}
class Zi extends Fu
{
int num=9;
Zi()
{
super();
//显示初始化
System.out.println("Zi constructor run..."+num);
}
void show()
{
System.out.println("zi show run..."+num);
}
class Test1
{
public static void main(String[] args)
{
new Zi();
}
}
输出:Zi constructor run...0
Zi constructor run...9
对象初始化demo2:
class FU
{
Fu()
{
System.out.println(" fu constrator run...");
show();
}
void show()
{
System.out.println("fu show run...");
}
}
class Zi extends Fu
{
int num=9;
{
System.out.println(" zi constrator code..."+num);
num=10;
}
Zi()
{
super();
//显示初始化
//构造代码块运行
System.out.println("constrator run..."+num);
}
void show()
{
System.out.println("zi show run...");
}
}
class Test2
{
public static void main(String[] args)
{
new Zi();
}
}
输出:
fu constrator run...
zi show run...0
constrator code...9
zi constrator run...10
final关键字:
final可以修饰类、方法、变量
final修饰的类不可以被继承
final修饰的方法不能被覆盖
final修饰的变量是一个常量,只能被赋值一次
内部类只能访问被final修饰的局部变量
final是固定显示初始化值
public static final double PI=3.14;全局常量
抽象类:
特点:
1.方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰,
抽象方法必须定义在抽象类中。该类也必须被abstract修饰
2.抽象类不可以被实例化,因为调用抽象方法没有意义;
3.抽象类必须有其子类覆盖了所有的抽象方法后,该子类才可以被实例化,否则这个类还是抽象类。
细节:
1.抽象类中有构造函数吗?
有,用于给子类对象进行实例化。
2.抽象类可以不定义抽象方法吗?
可以的。但是很少见,目的是不让该类创建对象。AWT的适配器对象就是这种类。通常这种类中的方法有方法体,没有内容。
abstract class Demo
{
void show1(){};
void show2(){};
}
3.抽象关键字不可以和那些关键字共存?
private static final
4.抽象类和一般类的异同点
相同点:抽象类和一般类都是来描述事物的,都在内部定义了成员。
不同点:
1.一般类有足够的信息描述实物,抽象类描述事物的信息有可能不足
2.一般类中不能定义抽象方法,只能定义非抽象方法。抽象类中可定义抽象方法,也可以定义非抽象方法。
3.一般类可以被实例化。抽象类不可以被实例化。
5.抽象类一定是个父类吗?
是的,因为需要子类覆盖其方法才可以对子类实例化。也可以是子类,但不能是最底层,不然就不能被覆盖。
接口:当一个类中的方法都是抽象方法的时候,这时候可以将该抽象类用另外一种形式定义和表示,就是接口interface
对于接口中的常见成员,这些成员都有固定的修饰符,接口中的修饰符都是公共的权限。
1.全局变量:public static final int t=4;
2.抽象方法:public abstract void show();
interface Demo{
public static final int num=4;
public abstract void show();
}
类与类是继承关系,类与接口是实现关系。
接口不可以实例化,只有在由类实现了接口中的所有抽象方法后,该子类才可以实例化,否则这个类就是一个抽象类。
在java中不直接支持多继承,会出现调用的不确定性。但是支持多实现,一个类可以实现多个接口。
一个类在继承了一个类的同时,还可以实现多个接口。接口的出现避免了单继承的局限性。
接口与接口之间是继承关系,而且可以多继承。
接口与抽象类的异同点 :
相同的点:都是不断向上抽取的。
不同点:1.抽象类需要被继承,而且只能被单继承
接口需要被实现,而且是可以多实现。
2.抽象类中可以定义抽象方法和非抽象方法,子类集成后可以直接使用非抽象方法
接口中只能定义抽象方法,必须由子类实现
3.继承是is a关系,在定义的该体系的基本内容
接口是like a关系,在定义体系的额外功能。
多态:一个对象对应着不同类型
父类或者接口的引用指向子类的对象(一个对象两种形态)
好处:提高了代码的扩展性,前期定义的代码可以使用后期的内容;
弊端:前期定义的内容不能使用(调用)后期子类的特有功能。
前提:
1.必须有关系:继承,实现
2.要有覆盖
向上转型:作用是限制对特有功能的访问,提高扩展性。把猫对象提升为动物对象,猫特有的功能动物无法访问。
向下转型:目的是为了使用子类中特有的方法。把动物向下转换为猫,就可以使用猫特有的方法。
注意:对于转型,自始至终都是子类在做着类型的变化。
instanceof:用来判断对象具体的类型,只能用于引用数据类型的判断。
if(a instanceof Cat)//通常在向下转型前,用于健壮性判断。
多态时编译运行特点:
1.成员变量
编译时:参考引用型变量所属的类中是否有调用的成员变量。有,则编译通过;无,则编译失败。
运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该类所属的成员变量。
简单说:编译和运行都看左边。
2.成员函数(非静态)
编译时:参考引用型变量所属的类中是否有调用的成员函数。有,则编译通过;无,则编译失败。
运行时:参考对象所属的类中是否有调用的函数。
简单说:编译看左边运行看右边。
3.静态函数
编译时:参考引用型变量所属的类中是否有调用的静态函数。有,则编译通过;无,则编译失败。
运行时:参考引用变量所属的类中是否有调用的静态方法。
简单说:编译和运行都看左边。
其实对于静态方法,是不需要对象的。直接使用类名调用即可。
内部类
字节码:Outer$Inner
内部类的特点:类似于的一个成员,内部类可以被成员修饰
符修饰
1.内部类可以直接访问外部类中的成员
2.外部类要想访问内部类,必须建立内部类的对象
用途:一般用于类的设计
分析事物时,发现该事务中描述还有事务,而且这个事物还在访问被描述事物的内容,这时就把还有的事物定义为内部类的述。
如果内部类定义了静态成员,该内部类也必须是静态的。
1.直接访问外部类中的内部类成员
class Outer
{
private int num=3;
class Inner
{
void show(){
System.out.println("Inner run...");
}
}
public void method(){
Inner in=new Inner();
in.show();
}
}
class Demo1
public static void main(String[]args)
{
Outer.Inner in=new Outer().new Inner();
in.show();
}
}
2.如果内部类是静态的。相当于一个外部类。
class Outer
{
private static int num=3;
static class Inner
{
void show(){
System.out.println("Inner run..."+num);
}
}
public void method(){
Inner in=new Inner();
in.show();
}
}
class Demo1
public static void main(String[]args)
{
Outer.Inner in=new Outer.Inner();
in.show();
}
}
3.如果内部类是及静态的,成员也是静态的。
class Outer
{
private static int num=3;
static class Inner
{
void show()
{
System.out.println("Inner run..."+num);
}
static void function()
{
System.out.println("function run..."+num);
}
}
public void method(){
Inner in=new Inner();
in.show();
}
}
class Demo1
public static void main(String[]args)
{
Outer.Inner.function();
}
}
为什么内部类能直接访问外部类的成员呢?
那是因为内部类持有了外部类的引用。
class Outer
{
int num=3;
class Inner
{
int num=4;
void show()
{
int num=5;
System.out.println(this.num);
System.out.println(Outer.this.num);//调用外部类的num
}
}
void method()
{
new Inner().show();
}
}
class InnerClassDemo2
{
public static void main(String[] args)
{
new Outer().method();
}
}
内部类可以放到局部位置上,内部类在局部位置上只能访问局部中被final修饰的局部变量。
class InnerDemo
{
int num=3;
void method()
{
final int x=9;
class Inner
{
void show()
{
System.out.println("show..."+x);
}
}
Inner in=new Inner();
in.show();
}
}
class InnerClassTest
{
public static void main(String[] args)
{
new Outer().method();
}
}
匿名内部类:就是内部类的简写形式
前提:内部类必须继承或者实现一个外部类或者接口。
匿名内部类:匿名子类对象
格式:new 父类or接口名(){之类内容}
使用:new 父类or接口名(){之类内容}.方法名();
abstract class DemoFu
{
void show();
}
class Outer
{
int num=3;
/*
class Inner extends DemoFu//内部类
{
void show()
{
System.out.println("show.."+num);
}
}
*/
public void method()
{
//Inner in=new Inner();
//in.show();
new DemoFu()//匿名内部类
{
void show()
{
System.out.println("show.."+num);
}
}.show;
}
}
class InnerClassTest
{
public static void main(String[] args)
{
new Outer().method();
}
}
当函数参数是接口类型时,而且接口的方法不超过3个,可以使用匿名内部类作为实际参数进行传递。
异常:是在运行时期发生的不正常情况
在java中用类的形式对不正常的情况进行描述和封装情况。
描述了不正常的情况的类就叫异常类。
以前正常流程代码和问题处理相结合,现在将正常流程代码和问题处理代码分离,提高阅读性。
其实异常类就是java通过面向对象思想将问题封装成对象。
用异常类进行处理,不同的问题用不同的类进行具体描述。
问题很多,意味着描述的类也很多,将其共性进行向上抽取,形成了异常体系。最终问题(不正常情况)就分为两类
Throwable:可抛
无论是Error还是Exception,问题发生就应该可抛,让调用者知道并处理,
该体系的特点就在于Throwable及其所有子类都具有可抛性。
Error:一般不可处理的
Exception:可以处理的
可抛性到底是什么?怎么体现可抛性呢?
通过两个关键字体现:throws 和 throw ,凡是被这两个关键字修饰操作的类和对象都具备可抛性。
Error特点:是由JVM抛出的严重性问题。这种问题一般不会针对性的处理,直接修改程序。
该体系的特点:子类的后缀名都是父类名作为后缀,阅读性很强。
自定义异常:如果要让一个类成为异常类,必须要继承异常体系,因为只有成为异常体系的子类才有资格具备可抛性。
才可以被两个关键字操作:throws和throw
异常的分类:
编译时被检查异常:只要是Exception和其子类都是,除了特殊子类RuntimeException。这种问题一旦出现,希望在编译时被检测到,让这种问题有对应的处理方式,这样的问题都可以处理。
编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类。
这种问题无法让功能继续,运算无法进行,更多的是调用者的原因导致的或者引发了内部状态的改变导致的。
这种问题一般不处理,直接编译通过,在运行时让调用时的程序强制停止,让调用者对代码进行修正。(不用throws)
所以在自定义异常时,要么继承Exception,要么继承RuntimeException.
throws和throw的区别:
1.throws直接用在函数上,throw用在函数内;
2.throws抛出的是异常类,可以抛出多个,用逗号隔开,throw抛出的是异常类。
throws声明异常是为了让调用者知道异常并处理。
异常处理捕捉的形式:这是可以对异常进行针对性处理的形式。
try
{
//需要本检测的代码块
}
catch(异常类 变量)//该变量用于接受发生异常的对象
{
//处理异常的代码
}
finally
{
//一定会被执行的代码
}
遇到多个catch:父类的catch放到最下面
异常处理的原则:
1.函数内部如果抛出检测的异常,那么函数必须声明,负责必须在函数内部用try,catch捕捉,否则编译失败;
2.如果调用到了声明异常的函数,要么try要么throws,负责编译失败;
3.什么时候try什么时候catch?
功能自己可以解决就catch,解决不了就用throws告诉调用者,由调用者处理。
4.一个功能如果抛出多个异常,那么调用时,必须有对应的多个catch进行针对性的处理,
内部又多了需要检测的异常,就抛出几个异常,抛出几个,就catch几个。
finally通常用于关闭释放资源
try、catch、finally代码块的特点:
1.try catch finally;
2.try catch(多个)当没有资源释放时,就可以不定义finlly;
3.try finally。异常无法catch处理,但是资源需要关闭。
异常注意事项:
1.子类在覆盖方法时,父类的方法如果抛出了异常,那么子类的方法也只能抛出父类的异常或者该类的子类。
2.如果父类抛出多个异常,那么子类只能抛出父类异常的子集。
简单说:子类覆盖父类只能抛出父类的异常或子类或者子集。
如果父类的方法没有抛出异常,那么子类覆盖时决不能抛,只能try。