1、类和对象
1.1 类的定义和调用
#类: 类是对一种事物的行为和属性进行抽象化、模版化的方式,只是描述一种事物的特征和行为,不是具体的一个事物!
#对象: 对类进行实例化出来的实体对象,该对象具有类中所有属性和行为,同时也可能还具备不同属性值和不同的行为方式!就像人又分黑人、白人、黄种人,同时还分女人、男人、变性人、太监等!那人就是一个类,这些太监、黑人就是类的不同的对象!
#定义格式:
public class 类型{
//类成员变量
//类方法
}
#范例:
public class Person{
String name;
int age;
public static void run(){
}
public static void reflection(){
}
}
#调用:
Person p = new Person();
p.name;
p.age;
##### 1.2 构造器
1、# 什么是构造器?
你可以理解为:专门给类对象进行初始化工作的一种方法!当你定义了一个类之后,自带一个默认无参的构造器方法(隐藏显示),等同于python中用于初始化实例对象的__init__魔法方法!
特征: 1、跟类名相同 2、无参数和返回值
作用: 帮助类对象初始化工作
2、# 构造器分类:
*无参构造器:
public class Dog {
public String name;
public int age;
public boolean sex;
//这里自带了默认的构造器
//无定义构造器,字段值为默认值: 数字-0, 对象引用-null, boolean-false;
public static void main(String[] args) {
Dog gzq = new Dog();
System.out.println(gzq.age);
System.out.println(gzq.name);
System.out.println(gzq.sex);
}
}
输出:
0
null
false
*有参构造器:
public class Dog {
public String name;
public int age;
public boolean sex;//false表示女,true表示男
public Dog(String aname,int aage,boolean asex){
this.age = aage;
this.name = aname;
this.sex = asex;
}
//无定义构造器,字段值为默认值: 数字-0, 对象引用-null, boolean-false;
public static void main(String[] args) {
// Dog g1 = new Dog();
Dog g2 = new Dog("旺财",3,true);
// System.out.println(g.age);
// System.out.println(g.name);
// System.out.println(g.sex);
// System.out.println();
System.out.println(g2.age);
System.out.println(g2.name);
System.out.println(g2.sex);
}
}
输出:
3
旺财
true
3、#构造器使用情况:
*一个类中只有默认无参构造器时:
系统自定调用无参构造器对类对象进行初始化赋值等操作
*一个类中有无参和与有参构造方法时:
*当你创建无参的实例对象时,系统去调用无参构造器进行初始化时会找不到该类默认的无参构造方法!如果想还是使用无参构造器进行创建无参对象时,可以自定义写出来!
*当你创建有参的实例对象时,先把对象里传入的具体数值赋值给类字段,然后调用有参构造器进行赋值给该对象,实现初始化赋值!
代码验证:
public class Dog {
public String name;
public int age;
public boolean sex;//false表示女,true表示男
//无参构造器
public Dog() {
}
//有参构造器1
public Dog(String aname,int aage){
this.age = aage;
this.name = aname;
}
//有参构造器2
public Dog(String aname,int aage,boolean asex){
this.age = aage;
this.name = aname;
this.sex = asex;
}
//无定义构造器,字段值为默认值: 数字-0, 对象引用-null, boolean-false;
public static void main(String[] args) {
Dog g1 = new Dog();
Dog g2 = new Dog("旺财",3);
Dog g3 = new Dog("旺财",3,true);
System.out.println(g1.age);
System.out.println(g1.name);
System.out.println(g1.sex);
System.out.println();
System.out.println(g2.age);
System.out.println(g2.name);
System.out.println(g2.sex);
System.out.println();
System.out.println(g3.age);
System.out.println(g3.name);
System.out.println(g3.sex);
}
}
输出:
0
null
false
3
旺财
false
3
旺财
true
小结(构造器):
1、定义构造器方法时,方法名必须与类名相同,且不能有返回值 (但是不能用 void 声明,报错)
2、同一个类中构造器是可以重载的,根据参数列和类型进行调用
3、当一类定义了有参构造器,想调用无参构造器去创建无参对象时,无参构造器必须显示的写出来(通过反编译文件可以看出,当定义有参构造器后,无参构造器就自动消失了,所以得再次写上),不然报错找不到该构造器
疑问?# 此时我有个疑问?既然有参构造器是通过创建对象时把数值赋值给类字段——>再调用有参构造器进行this.类字段 = 参数名进行该实例对象的值初始化,那么无参构造器是怎么把0、null、false等初始值赋值给无参对象的呢?
*我的猜想:
1、要么就是当定义类字段时,类字段什么默认值都没赋值,类字段赋值和类字段对对象赋值都在无参构造器里实现,只是我们看不到实现代码?
2、要么就是当定义类字段时,就已经给类字段赋值为对应的默认值(0或null了),然后调用无参构造器给对象赋值进行初始化?(我倾向这种)
1.4.1 this 与 super 用法总结
# this
*含义: 在java中,this表示类实列对象,等同于python中的self!
*用处1:
用于在方便区分形参和实参!当我们在类中想定义一些对类成员变量进行修改获取操作时,定义的形参名一般与类成员变量名相同 (调用子类和父类的方法和属性)
#范例代码1
//定义父类
public class Country {
protected String name = "国家"; //Country类成员name="中国";
public void print(){
System.out.println("执行父类方法输出:Country");
}
}
//定义子类
public class Chinese extends Country {
private String name = "中国";
public void print(){
System.out.println("执行子类方法输出:Chinese");
}
//定义测试方法test()
public void test(String name){
//调用属性父类和子类的属性
System.out.println(name); //输出对象调用该方法时的实参
System.out.println(this.name);//输出该子类自己的类成员变量值
System.out.println(super.name);//输出该类上一级父类的类成员变量值
System.out.println();
}
//定义测试方法test1()
public void test1(){
print(); //这个调用的是当前最近的子类print()方法
this.print(); //这个调用的是子类本身的print()方法
super.print(); //这个调用的是父类的print()方法
}
//程序入口函数
public static void main(String[] args) {
Chinese c = new Chinese();
c.test("上海");
c.test1();
}
}
输出:
上海
中国
国家
执行子类方法输出:Chinese
执行子类方法输出:Chinese
执行父类方法输出:Country
范例2(构造器中的this用处):
// 验证类
public static void main(String[] args) {
Dog d = new Dog("旺财",3);
d.showinfo();
new Dog("公").showinfo();
}
//测试类
class Dog{
public String name;
public int age;
public String sex;
public Dog(String name,int age){
//this.name = name;
//this.age = age;
name = name;
age = age;
}
public Dog(String sex){
this.sex = sex;
}
public void showinfo(){
System.out.println("name: "+name+"|"+"age: "+age);
System.out.println("sex: "+ sex);
}
输出:
name: null|age: 0
sex: null
name: null|age: 0
sex: 公
小结:
1、this代表当前类对象本身,super代表父类对象本身!
2、当子类中和父类有同名方法时,子类调用这个同名方法默认是调用离的近这个类的同名方法; 当子类中使用this.同名方法调用时,调用的是当前类的这个方法; 当使用super.同名方法时,调用的是父类的这个同名方法!
3、super无法访问继承父类的私有方法和属性
4、在类构造器中没有this,无法为实例对象的属性赋值
5、(this可以这样理解)每个被创建的新对象在堆中都隐藏一个this属性,它只指向该对象自己!就像生活中,你说我和你说我指的是说我的那个人
*用处2:
构造器
#范例代码1:
public class Chinese extends Country {
private String name = "中国";
//子类无参构造
public Chinese() {
//super();
System.out.println("子类Chinese执行了无参构造器");
}
public void print(){
System.out.println("执行子类方法输出:Chinese");
}
//定义测试方法test()
public void test(String name){
//调用属性父类和子类的属性
System.out.println(name); //输出对象调用该方法时的实参
System.out.println(this.name);//输出该子类自己的类成员变量值
System.out.println(super.name);//输出该类上一级父类的类成员变量值
System.out.println();
}
//定义测试方法test1()
public void test1(){
print(); //这个调用的是当前最近的子类print()方法
this.print(); //这个调用的是子类本身的print()方法
super.print(); //这个调用的是父类的print()方法
}
//程序入口函数
public static void main(String[] args) {
Chinese c = new Chinese();
//c.test("上海");
//c.test1();
}
}
输出:
父类Country执行了无参构造器
子类Chinese执行了无参构造器
小结:
1、当子类继承父类时,创建子类对象时会先执行父类的无参构造器,然后再执行子类无参构造器,子类构造器第一行隐藏了super()方法
2、子类构造器里调用父类构造器句super()方法必须再第一行
#范例代码2
//父类
public class Country {
protected String name = "国家"; //Country类成员name="中国";
//父类无参构造器
public Country() {
System.out.println("父类Country执行了无参构造器");
}
//父类的有参构造器
public Country(String name){
System.out.println("执行了父类的有参构造器输出实:"+ name);
}
}
//子类
public class Chinese extends Country {
private String name = "中国";
//子类无参构造
public Chinese() {
super();
System.out.println("子类Chinese执行了无参构造器");
}
//子类有参构造器1
public Chinese(String name){
super(name);
System.out.println("子类Chinese执行了有参构造器1输出参数:"+ name);
}
//子类有参构造器2
public Chinese(String name,int age){
this(name);
System.out.println("子类Chinese执行了有参构造器2输出参数:"+ name);
System.out.println("子类Chinese执行了有参构造器2输出参数:"+ age);
}
// public void print(){
// System.out.println("执行子类方法输出:Chinese");
// }
//程序入口函数
public static void main(String[] args) {
Chinese c = new Chinese();
Chinese c1 = new Chinese("中国");
Chinese c2 = new Chinese("中国",5000);
}
}
输出:
父类Country执行了无参构造器
子类Chinese执行了无参构造器
执行了父类的有参构造器输出实:中国
子类Chinese执行了有参构造器1输出参数:中国
执行了父类的有参构造器输出实:中国
子类Chinese执行了有参构造器1输出参数:中国
子类Chinese执行了有参构造器2输出参数:中国
子类Chinese执行了有参构造器2输出参数:5000
总结:
1、super(参数):调用基类中的某一个构造函数(应该为构造函数中的第一条语句)
2、this(参数):调用本类中另一种形成的构造函数(应该为构造函数中的第一条语句)
3、super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
4、this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用
5、super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
6、super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。
7、super()和this()均需放在构造方法内第一行。尽管可以用this调用一个构造器,但却不能调用两个。
8、this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
9、this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
10、从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
1.3 一个方法执行时的内存分配图
1.4 构造器能被重写吗?为什么?
#首先构造器时不能重写的,但是可以重载,所以会出现一个类中有多个构造器方法!为什么不能重写,因为构造器是不能子类去继承父类的构造器!那为什么不能继承?
解释:
1、子类继承父类后,运行子类时先运行父类的构造器方法帮助子类进行初始化工作! 父类会自动调用父类构造方法
2、构造器方法名与当前类名相同,而父类名与子类名绝不相同!
3、如果子类继承了父类的构造器,那不就是在子类里写一个父类名的无参无返回值得普通方法吗,父类构造器它自动被父类调用运行,要继承父类构造器有什么作用?
引用洞主一句名言: 可以但没必要!!!
# 构造器重载代码:
public class Person {
public String sex;
public String name;
public int age;
//默认构造器显性写出来
public Person(){}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
//两个参数的构造器
public Person(String sex,String name){
this.sex = sex;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//三个参数的构造器
public Person(String sex,String name,int age){
this.sex = sex;
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person("变性人","金星");
Person p3 = new Person("太监","李莲英",58);
System.out.println("sex:"+p1.getSex() + "--name:" + p1.getName());
System.out.println("sex:"+p2.getSex() + "--name:" + p2.getName());
System.out.println("sex:"+p3.getSex() + "--name:" + p3.getName());
}
}
输出:
sex:null--name:null
sex:变性人--name:金星
sex:太监--name:李莲英
小结:
1、构造器可以进行重载,
2、构造器不能被重写,因为子类不能继承父类的构造器!(就算继承,也是子类中无参无返回的同父类名的普通方法,没什么用处!)
1.5 成员变量(类变量)与局部变量有什么区别?
1、语法结构上:
*类变量:
1、属于类的属性,位于类方法之上
2、可以被修饰符public、protected(受保护的)、default(默认)、private、final(常量)所修饰的
*局部变量:
1、一般属于方法体中的变量或参数或代码块中,只能被final常量修饰符修饰!
2、内存存储上:
*类变量:
1、如果没有被static修饰,属于类,存储在方法区中;如果被static修饰,属于该类的实例对象,而类实例对象存储与堆中,所以也在堆中
*局部变量:
1、存储在栈中
3、生命周期上:
*类变量:
1、随着类的创建而存在,随着类的清洗而消失!
*局部变量:
1、随着方法的运行完就弹出栈中
4、初始化上:
*类变量:
1、如果不给类变量初始值,系统会根据变量类型赋值初始值(基本类型是0,引用类型是null)
*局部变量:
1、局部变量必须手动赋值,系统不作默认初始化!
1.6 new的作用是什么?实例对象与对象引用有什么区别?
1、new的作用:
Dog d1 = new Dog(“旺财”);
*内存分配:
1、先去堆中开辟一个内存空间来存储Dog(“旺财”)和它的地址,然后初始化!
2、创建了实例对象Dog(“旺财”),把Dog(“旺财”)在堆中的存储地址赋值给对象引用d1,对象d1指向Dog(“旺财”)
*执行顺序:
1、先创建一个Dog实例对象,把初始值"旺财"赋值给类字段(其实就是类成员变量)String name,然后调用该类的有参构造器方法把该初始值赋值给给实例对象(this.name = name)
2、如果是new Dog(),先检查new对象是否有参——>无参数,然后对类进行是否定义了有参/无参构造器的判断,确定没有定义有参构造器方法,调用默认无参构造器进行初始化(默认初始化值0或null或false给类字段进行赋值)
2、( 1、实体对象存于堆中,本身存储的是具体值; 对象引用存储在栈中,本身存储对象在堆中的地址!2、实例对象可以有1或n个引用指向它; 对象引用只能有0或1个指向对象)
1.7 对象相等 与对象引用相等有什么区别?
#对象相等: 指的是两个对象存储在堆中的具体数组相等
#对象引用相等: 指的是两个对象引用指向的是否是同一个对象(同一个存储地址)
2、面向对象三大特征
2.1 封装
#顾名思义,就是把类属性封装在内部隐蔽起来,再定义一些可供操作这些属性的方法暴露出来给外部使用!就像我们使用第三方接口一样,只给你用,不会给你看具体的实现细节和类属性!
#封装的目的:
1、除了隐藏属性和细节外,更重要思想是为了是实现高聚集,低耦合、事物抽象化后在模块化!用类组织代码,用实例对象组织数据!
#代码:
//银行账户
import java.math.BigDecimal;
public class bankAccount {
String name;
BigDecimal money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getMoney() {
return money;
}
public void setMoney(BigDecimal money) {
this.money = money;
}
}
2.2 继承
1、#顾名思义,就是子类可以继承父类的所有方法和属性,增加了代码的可复用性!使用关键字extends继承
# 代码:
父类文件:
public class Father {
//金额public class Father {
//金额暂时先用double类型
public double property = 10000;
protected int house;
int car;
private int friend;
public double getProperty() {
return property;
}
// public void setProperty(double property) {
// this.property = property;
//}
public int getHouse() {
return house;
}
public void setHouse(int house) {
this.house = house;
}
public int getCar() {
return car;
}
public void setCar(int car) {
this.car = car;
}
}
子类文件:
public class Son extends Father{
double myMoney;
int myHouse;
int myCar;
public double getMyMoney() {
return myMoney;
}
public void setMyMoney(double myMoney) {
this.myMoney = myMoney;
}
//把修改父类属性的方法拿到子类里也可以实现对父类属性的修改
public void setProperty(double property) {
this.property = property;
}
}
测试文件:
public class appliction {
public static void main(String[] args) {
Son s = new Son();
System.out.println("通过子类实例对象访问原始类属性:" + s.property);
//通过setProperty方法修改父类属性
s.setProperty(1_0000_0000);
s.setHouse(2);
System.out.println("通过setProperty方法修改父类属性:" + s.property);
System.out.println("通过setProperty方法修改父类属性:" +s.house);
System.out.println("通过setProperty方法修改父类属性:" +s.car);
//通过子类对象.父类属性修改父类属性
s.property = 1;
System.out.println("通过子类对象.父类属性修改父类属性" + s.property);
Father f = new Father();
}
}
输出:
通过子类实例对象访问原始类属性:10000.0
通过setProperty方法修改父类属性:1.0E8
通过setProperty方法修改父类属性:2
通过setProperty方法修改父类属性:0
通过子类对象.父类属性修改父类属性1.0
2、小结:
#特点:
1、在java中只能单继承,不能像python多继承从而出现砖石继承现象!
2、子类继承了父类的所有方法和属性,包括父类的private方法和属性,但是不能访问!
3、继承的同时子类自己也可以定义自己方法和属性
4、子类可以通过(super()) 重写父类的 (公共的)方法达到自己想要的效果,不能重写父类的(属性)
# 注意:
1、父类实例对象不能访问子类的所有方法和属性
2、子类实例对象可以访问父类的(public、protected、default(什么修饰符都不写就是默认default, 本身没有这个修饰符))所修饰的类变量和方法,除了私有private修饰的变量和方法!
3、(前提是:不被private所修饰) 子类实例对象可以通过(修改父类属性的方法)修改父类的原始属性,如论这个(修改父类属性的方法)是在父类还是在继承父类的子类里都可以!
2.21 重写
# 被static修饰符子类的方法,因为被static修饰后方法只属于类不属于对象
代码::
public class A{
public static void test(){
System.out.println("test-->A")
}
}
public class B extends A{
public static void test(){
System.out.println("test-->B")
}
public static void main(String[] args){
A a = new A();
a.test();
A b = new B();//对象引用b属于A类型,调用的是A类型的test()方法
b.test();
b b1 = new B();
b1.test();
}
}
输出:
test——>A
test——>A
test-->B
#不被static修饰
代码2:
public class A{
public void test(){
System.out.println("test-->A")
}
}
public class B extends A{
public void test(){
System.out.println("test-->B")
}
public static void main(String[] args){
A a = new A();//A类的引用指向A类,调用的是A类的test()
a.test();
B b1 = new B();//B类的引用指向B类,调用的是B类的test()
b1.test();
A b = new B();//A类的引用指向B类,所以调用的是A类的test()方法
b.test();
A a1 = new A();//A类的引用指向A类,A类的方法被重写后,还是原来那个方法
a1.test();
}
}
输出:
test——>A
test-->ABA
test-->ABA
test——>A
小结(重写):
1、子类与父类的方法名相同
2、方法参数列表相同
3、子类方法的修饰符作用范围可以扩大但不能缩小。如父类方法使用protected修饰符,子类方法修饰符可以使用protected或者public
4、子类方法异常范围只能缩小不能变大(子类定义的异常范围不能大于父类方法的异常范围)
5、父类方法只能在被继承的子类中重写
6、子类重写父类方法后,父类方法并没有改变
*不能重写:
1、被static、final修饰的方法不能重写
2、子类构造器里不能重写父类构造器方法
2.3.2 super使用
#当你想在子类中调用父类的重写方法时,可以用super
代码:
public class A{
public void test(){
System.out.println("test--A")
}
}
public class B extends A{
public void test(){
super.test();//调用了父类被重写的test()方法
System.out.println("test--B")
}
public static void main(String[] args){
A a = new B();
a.test();
}
}
输入:
test——>A
test-->ABA
2.3 多态
#什么是多态?
[https://www.cnblogs.com/xwhxxyxhxlfl/articles/14403165.html]()
2.3.1 instanceof 关键字
# instanceof使用:
x instanceof y
检查x是否和y存在父子线之间的关系
# 代码(instanceof):
public class superClass {
public void print(){
System.out.println("父类superClass打印了superClass");
}
//把测试方法定义在父类中(当然放在子类都行)
public static void main(String[] args){
superClass sup = new superClass();
System.out.println(sup instanceof superClass);
System.out.println(sup instanceof Object);
System.out.println(sup instanceof sonClass1);
System.out.println(sup instanceof sonClass2);
System.out.println();
superClass son1 = new sonClass1();
System.out.println(son1 instanceof superClass);
System.out.println(son1 instanceof Object);
System.out.println(son1 instanceof sonClass1);
System.out.println(son1 instanceof sonClass2);
System.out.println();
superClass son2 = new sonClass2();
System.out.println(son2 instanceof superClass);
System.out.println(son2 instanceof Object);
System.out.println(son2 instanceof sonClass1);
System.out.println(son2 instanceof sonClass2);
}
}
//定义子类2并继承父类
public class sonClass2 extends superClass{
public void print(){
System.out.println("子类sonClass1打印了B");
}
}
//定义子类1并继承父类
public class sonClass1 extends superClass{
public void print(){
System.out.println("子类sonClass1打印了A");
}
}
小结(instanceof):
1、只要存在父子关系直线上的对象返回都是true,不管是间接父子还是直接父子关系都是true
2、兄弟的同级关系返回false
2.3.2 对象类型转换
# 转换规则(跟基本类型转换一致):
代码:
public class superClass {
public void print(){
System.out.println("父类superClass打印了superClass");
}
//把测试方法定义在父类中(当然放在子类都行)
public static void main(String[] args){
sonClass1 son1 = new sonClass1();
superClass sup = son1;
sup.print();
//sup.test(); //子类转换承父类类型,丢失了子类自己的test()方法,只能用跟父类同名的方法
superClass sup1 = new superClass();
sonClass1 son2 = (sonClass1) sup1;
}
}
//定义子类1并继承父类
public class sonClass1 extends superClass{
public void print(){
System.out.println("子类sonClass1打印了A");
}
public void test(){
System.out.println("test");
}
}
//定义子类2并继承父类
public class sonClass2 extends superClass{
public void print(){
System.out.println("子类sonClass1打印了B");
}
}
小结(对象类型转换):
1、子类转换成父类类型:
自动转换,转换成父类后只能调用子类和父类同名的方法(重写的方法),关于子类自己的其他方法不能使用
2、父类转换成子类类型;
必须强制转换。转换规则如(基本数据类型转换一样),转换子类对象后可用子类所有方法!
2.4 抽象类
# 用途:
其实就是相当于做了一个类模板,这个模板只定义了类变量名和方法名,但并没有值和方法的实现!把重复性高的操作放到抽象类中定义
# 定义(使用关键字abstract):
代码:
//定义抽象类Test
public abstract class Test {
private String name;
public int number;
public abstract void print();
public Test() {
System.out.println("这是抽象类的构造器");
}
}
//定义子类
public class Test1 extends Test{
public Test1(){
super();
System.out.println("这是子类构造器");
}
public void print(){
System.out.println("这是子类的print方法");
}
public static void main(String[] args) {
Test1 t = new Test1();
t.print();
}
}
小结(抽象类特点):
1、抽象类不能new对象,也不能编写方法实现内容
2、抽象类也有构造器,子类构造器也能调用抽象父类的构造器
2.5 接口
普通类:只有具体的实现
抽象类:具体的实现和抽象方法
接口:只有规则(类的约束),实现了约束和实现分离
#接口的规范:就是定义一组规则,像法律一样人人都必须遵守!
#什么是接口?
答:接口是定义一系列方法,然后通过实现类一一重写并实现接口中定义的方法!相当于你的计划书,计划书里写着为了实现某个目标,我接下来的操作步骤应该先干嘛再干嘛....实现类就是你执行计划里的步骤过程!
#接口定义(interface关键字)
//定义接口Test1
public interface Test1 {
//int age;不能定义没有初始值的类变量
int age = 100;
//增
void increase(String name);
//删
void delete(String name);
//改
void modify(String name);
//查
void query(String name);
public static void main(String[] args) {
//new Test1(); 不能创建对象,因为没有构造器
}
}
//定义接口Test2
public interface Test2 {
void test(String name);
}
//定义实现类
public class Test implements Test1,Test2 {
@Override
public void increase(String name) {
System.out.println(name);
}
@Override
public void delete(String name) {
System.out.println(name);
}
@Override
public void modify(String name) {
System.out.println(name);
}
@Override
public void query(String name) {
System.out.println(name);
}
@Override
public void test(String name){
System.out.println(name);
}
public static void main(String[] args) {
Test t = new Test();
System.out.println(Test.age);
t.increase("增");
t.delete("删");
t.modify("改");
t.query("查");
t.test("test");
}
}
输出:
100
增
删
改
查
test
小结(接口):
1、接口中可以定义类常量,不能定义没有初始值变量
2、接口不能创建实例对象,因为它不是类,没有构造器
3、接口实现了多继承。多个接口Test1、Test2可以同时被一个实现类Test继承实现
2.6 内部类 (成员内部类、局部内部类、匿名内部类、静态内部类)
1、#成员内部类(普通类嵌套)
代码:
public class OutClass {
private int id = 110;
protected String name = "小明";
//外部类方法
private void OutMethod1() {
System.out.println("这是外部类方法1输出id:"+id);
}
public void OutMethod2() {
System.out.println("这是外部类方法2输出name:"+name);
}
//内部类
public class InnerClass {
public void innerMethod() {
System.out.println("这是成员内部类方法");
}
//内部类方法获取外部类private变量
public void getId() {
System.out.println("内部类方法获取并打印了外部类私有变量id值为:" + id);
System.out.println("内部类方法获取并打印了外部类私有变量name值为:" + name);
//内部类方法可以直接获取控制外部类的所有类变量
OutMethod1(); //内部类方法可以直接调用外部类所有方法(包括private)
OutMethod2();
}
}
}
//测试方法
class test{
public static void main(String[] args) {
OutClass out = new OutClass();//实例化外部对象
OutClass.InnerClass inner = out.new InnerClass(); //通过外部类对象实例化内部类对象
inner.getId(); //内部类可以直接控制获取外部类的
//inner.OutMethod1();
//inner.OutMethod2();//内部类对象不能调用外部类方法任何方法和属性
out.OutMethod2();//外部类对象只能调用外部类除private修饰的方法
System.out.println(out.name);//外部类对象能获取外部类除私有外的所有的方法和属性
}
}
输出:
内部类方法获取并打印了外部类私有变量id值为:110
内部类方法获取并打印了外部类私有变量name值为:小明
这是外部类方法1输出id:110
这是外部类方法2输出name:小明
这是外部类方法2输出name:小明
小明
小结(成员内部类):
*外部类对象: OutClass out = new OutClass();
调用格式: 外部类名 外部类对象引用变量名 = new 外部类名()
*内部类对象: OutClass.InnerClass inner = out.new InnerClass();
调用格式: 外部类名.内部类名 内部类对象引用变量名 = 外部类对象引用变量名.new 内部类名()
*属性和方法:
1、内部类方法能调用任何类型的外部类属性和方法(不管是private还是public)
2、外部类方法能直接获取外部类属性
*对象:
1、内部类对象无法调用任何外部类的属性和方法(不管public还是private所修饰)
2、外部类对象只能获取外部类的公有方法和属性(只要不是private都可以)
2、#局部内部类
#定义在类方法中的内部类就是局部类,局部=方法!
#创建局部内部类格式:
public void func(int q){
class Inner{
}
// 创建局部内部类
Inner inner = new Inner(k);
inner.inner_f(100);
}
#代码举栗:
public class Outer {
private int i = 1;
private static int k = 2;
public void func(int q){
final int i = 3;
final int z = 4;
// 定义在方法内部, 局部内部类
class Inner{
int i = 300; // 可以定义与外部类同名的变量
// static int m = 30; 报错, 不可以定义静态变量
// 创建构造方法
Inner(int k){
}
int inner = 100;
void inner_f(int f){
System.out.println(k);
// 内部类没有与外部类同名的变量, 可在内部类直接访问外部类实例变量
System.out.println(this.i);
// 内部类与外部类变量名相同, 访问内部变量 this.内部变量
System.out.println(Outer.this.i);
// 变量名相同, 访问外部类变量 外部类类名.this.变量名
}
}
// 创建局部内部类
Inner inner = new Inner(k);
inner.inner_f(100);
}
public static void static_func(int y){
int d = 3;
class Inner{
private void func(){
// System.out.println(i); 编译错误, 定义在静态方法中的局部类不可以访问外部类的实力变量
System.out.println(k);
}
}
Inner inner = new Inner();
inner.func();
}
}
小结(局部内部类):
1、局部内部类创建方式,与上述都不同,应在对应方法内,new 内部类()
2、定义在实例方法中的局部类,可以访问到外部类所有变量|方法
3、定义在静态方法中的局部类,只能访问外部的静态变量|方法
4、局部内部类与外部类定义变量重名时,访问外部类变量(外部类.this.变量名)
3、#匿名内部类 (这里先跳过)
4、#静态内部类 (这里先跳过)
3、异常(Exception)
3.1 什么是异常
# 在生活中,如果我们每天都是开车去上班,结果半路车出问题了,上班迟到了!这就是生活上的异常!当我们在程序上给用户设置了一个输入数字的输入框,但是用户输入的是字符串,像这种就是程序上的异常!
3.2 异常的体系结构
#在java中,把异常当成对象来处理,并在java.lang.Throwable定义了一个异常的超类Throwable类!
#异常大致分为两类:
*Throwable:
*Error
* VirtulMachineError
*StackOverFlowError
*OutOfMemoryError
* AWTError
*EOFException
*FileNotFoundException
*Exception
*IOException
*EOFException
*FileNotFoundException
*RuntimeException
*ArithmeticException (算术异常)
*MissingResourceException
*ClassNotFoundException (找不到类)
*NullPointerException (空指针异常)
*IllegalArgumentException
*ArrayIndexOutOfBoundsException (数组下标越界)
*UnkownTypeException (类型异常)
# Error与Exception的区别
Error通常是灾难性错误,是程序无法控制和处理的,当出现这些异常时,jvm通常会强制终止该进程
而Exception是程序可以处理的,开发者应尽可能的去捕捉这些异常并处理!
3.3 java异常处理机制
#处理异常的五个关键字: try、catch、finally、throw、throws
try: 这里面写有可能出错的代码块,表示异常监控该区域
catch: 如果try监控区域出错,在这里设置异常对象(异常范围),并输出对应的异常信息
finally: 不管try区域是否出错,这里的代码都会执行。一般用于运行清理类型等收尾善后的工作
throw: 如果你确定那块代码有异常,用这个throw主动抛出异常。一般用于方法中,如果该方法无法处理该异常,可以主动往上抛出异常
throws: 如果一个方法没有捕获到检查性异常,可以使用throws关键字在方法尾部声明
#举例说明:
1、#栗子(try+catch+finally):
public class Test4 {
public static void main(String[] args) {
int a = 1;
int b = 0;
try {
System.out.println(a/b); //这里写可能出错的代码块
} catch (Exception e) { //这里定义可能异常的对象范围
System.out.println("程序出现异常,变量b不能为0");//这里声明异常信息
}finally {
System.out.println("finally");//这里定义异常的善后工作
}
}
}
输出:
程序出现异常,变量b不能为0
finally
2、#栗子(多重捕获异常处理):
public class Test4 {
public static void main(String[] args) {
int a = 1;
int b = 0;
try {
System.out.println(a/b);
} catch (Error e) {
System.out.println("Error"); //在多重捕捉异常时,定义异常对象规则遵循从小到大(异常的范围)
}catch (Exception e){
System.out.println("Exception"); //可理解为流程控制语句中的if,else if,最终只能走一个异常对象
}catch (Throwable e){
System.out.println("Throwable"); //这是异常对象的超父类
} finally {
System.out.println("finally");
}
}
}
输出:
Exception
finally
3#栗子(throw + throws):
import com.sun.javaws.exceptions.ErrorCodeResponseException;
public class Test4 {
public static void main(String[] args){
try {
new Test4().test1(10,0);
//如果光在方法中捕获异常,程序还是会强制终止,必须在异常代码中使用
try(){}catch(){}
} catch (ArithmeticException e) {
System.out.println("程序算术出现异常");;
}finally {
System.out.println("finally");
}
}
public void test1(int a, int b) throws ArithmeticException{
System.out.println(a/b);
throw new ArithmeticException(); //在方法中主动抛出异常
}
}
输出:
程序算术出现异常
finally
3.4 自定义异常
#举栗子:
//自定义异常类
public class myException extends Throwable {
private int data;//该参数data不能大于6,大于6就报异常
public myException(int data){
this.data = data;
}
@Override
public String toString() {
return "参数值异常-->"+data;
}
}
//定义测试类
public class Test5 {
void test(int n) throws myException{
System.out.println("参数n为-->"+n);
if (n>6){
throw new myException(n);
}else{
System.out.println("参数正常");
}
}
public static void main(String[] args) {
try {
new Test5().test(5);
} catch (myException e) {
System.out.println(e);;
}
try{
new Test5().test(7);
}catch(myException e){
System.out.println(e);
}
}
}
输出:
参数n为-->5
参数正常
参数n为-->7
参数值异常-->7
3.5 总结 (异常)
1、处理运行异常时,尽量使用逻辑合理规避同时使用try+catch捕捉处理
2、当使用多重捕捉catch异常时,设置异常对象遵循从小到大,可以在最后一层用Exception异常对象去捕捉以免遗漏异常
3、对不确定是否会出异常的代码块应使用try+catch进行异常处理
4、尽量去处理异常,而不是仅仅打印出异常
5、在工作中,根据业务需求和异常类型来处理异常
6、尽量使用finally去回收占用的内存资源