Java小知识点合集-面向对象

1关于Java中的值传递

关于Java中的值传递,其实就是存的是什么值,传出去就是什么值

  • 基本数据类型中存的是具体的数值
  • 引用数据类型中的存的是地址值
  • 类变量的引用定义在栈中,而对象定义在堆中,其中是一个指向的关系
package com.oop.day2;

public class ValueTransferTest {
    public static void main(String[] args) {
        /*
          关于变量赋值
          基本数据类型赋的值是变量所保存的数据值
          引用数据类型赋的值是变量的地址

          形参中的变量也是值传递,因为形参中的变量的生命周期随着方法的调用而创建
          随着方法的调用结束而删除

        */

        people p1 = new people();
        p1.number = 10;
        people p2 = new people();
        p2 = p1;
        p1.number = 22;
        System.out.println("p2 :" + p2.number + "\t" + "p1: " + p1.number );
    }
}
class people{
    int number;
}

输出:22 22

  • 对象是可以作为方法参数传递给方法的
//将对象作为参数传递给方法
public class CircleTest {
    public static void main(String[] args) {
        Circle c1 = new Circle();
        PassObject p1 = new PassObject();
        p1.printAreas(c1,5);
        System.out.println("circle" + c1.radius);
    }
}

class Circle{
    double radius;
    public double findArea(){
        return radius*radius*Math.PI;
    }
}
//这里的c.radius就是充分的利用了将对象作为函数参数传递给方法
class PassObject{
    public void printAreas(Circle c,int time){
        System.out.println("Radius\t\tArea");
        for(int  i = 1; i <= time; i++){
            c.radius = i;
            System.out.println(c.radius+"\t\t"+c.findArea());
        }
        c.radius = time + 1;
    }
}

2关于封装性

通过类中属性进行封装,从而使使用者无法直接对其属性进行操作,只可以通过规定好的具体方法去操作

2.1 常见使用

封装性的具体体现,如在类里面加了private属性,不可以在其他的类中对其直接进行(对象.属性)进行操作,而是需要通过设置get()和set()方法进行操作

2.2 权限控制符

  • public
    权限最大的修饰符,任意包内都可以进行调用
  • 缺省
    不定义权限控制符的话,默认其为缺省的,在一个包内可以随便调用
  • private
    权限最低的修饰符,只可以在类中进行随意调用,因为类是最小的控制单位了,想要进行操作的话,必须通过get和set方法进行调用

3构造器

由权限控制符加上类名和大括号构成,可分为有参构造和无参构造,在使用new关键字创建对象实例的时候,构造器被调用

public student()
{}

3.1含义

  • 构造器一般用来初始化类对象的属性
  • 构造器可以有多个,符合重载的规则
  • 可分为有参构造和无参构造,有参构造就是在new对象的时候传入参数即可

3.2构造器规则

  • 每个类都有默认的无参构造器,如果用户显示的定义了构造器,那么默认的无参构造器就会消失,需要用户显示定义
  • 与类同名
  • 无返回值

3.3子类继承父类时的补充

当父类显示的定义了构造器却没有定义无参构造器时,我们用子类继承父类会提示错误,这是因为定义子类后,子类会通过无参构造super()方法默认调用父类中的无参构造方法,而我们在父类中没有定义的话就会出现错误。也可以说是只要子类继承了父类,子类的构造器就要通过super()去调用父类的构造器,如果不通过super()调无参的,就通过super()调有参的也可以。

4 this关键字

  • this关键字可以用来修饰或调用:属性、方法、构造器
  • this理解为:当前对象 或 正在创建的对象
  • 在类的方法中,当形参名与属性名重名时,此时要使用this.变量的方式来代表其是属性而不是形参
  • this(形参列表)调用构造器要放在第一行,而且自己不能调自己

5 super关键字

5.1 super关键字调用属性、方法

当子类与父类中所定义的属性名相同时,我们通过super关键字来调用父类中的相关属性,当子类重写了父类中的方法时,我们通过super.方法来调用父类中被重写的这个方法。

5.2 super关键字调用构造器

  • 可以通过super(形参列表)的方式显示的调用父类中的构造器
  • super(形参列表)或this(形参列表)调用构造器时必须放在构造器的首行,super(形参列表)和this(形参列表)只能二选一
  • 如果在构造器中没有显示的给出super(形参列表)或者this(形参列表),则默认是super()去调用父类中的空参构造器

6 this和super调用构造器

  • 一个构造器调用另一个重载的构造器用this关键字
  • 子类调用父类的构造器用super关键字实现,但更能体现特点的是当子类继承父类之后,子类重写了父类的某个方法,此时我们在子类中还想继续使用父类的方法,这个是时候就需要使用super.方法名来调用父类的方法

7 多态

  • 将父类引用指向子类对象或(将子类对象赋给父类引用)就是多态,形式如下。其中student是person的子类。
person p = new student();
  • 具体的实现方式为虚拟方法调用,编译器会根据父类引用去调用方法,但是当运行时所执行的是子类中重写的方法。
  • 多态的虚拟方法调用只针对于的方法来说,对实例变量则无法调用。
  • 若子类重写了父类方法,就意味着子类里的方法彻底覆盖了父类的同名方法,系统不可能将父类的方法转移到子类当中去。
  • 对于实例变量则不存在这样的情况,即使在子类中定义了与父类中相同的实例变量,这个实例变量仍然不可能覆盖父类中的实例变量。(也可以说有关于属性的值看编译,即有关于属性,编译运行都看左)
package com.oop.sgg5.exer4;
public class test {
    public static void main(String[] args) {
        fo a = new fo();
        info b = a;
        if(a==b){
            System.out.println("-----地址值相等-------");
        }
        System.out.println(a.a);
        System.out.println(b.a);
        System.out.println(a.ao());
        System.out.println(b.ao());

    }
}
class info{
     int a = 10;
    public int  ao(){
        return this.a;
    }
}
class fo extends info{
     int a = 20;

    @Override
    public int ao() {
        return this.a;
    }
}
  • 多态在开发中常用的一种方式:方法中的参数使用的是父类的类型,而在我们实际的调用时所传入的确实子类的对象,这样的话,我们用这个传入的参数所调用的方法即是子类所重写的方法
  • 具体实现的例子可以看下面的代码,我们写具体方法的时候用的参数是传入的图像类,而调用的时候既可以传入圆形也可以传入矩形,而实现的计算面积的方法是圆形或者矩形自己所重写的计算面积的findArea()方法。
package com.oop.sgg5.exer6;

public class GeometricTest {
    public static void main(String[] args) {
        GeometricTest g = new GeometricTest();
        System.out.println(g.eaualsarea(new Circle("blue", 1.0, 2), new Circle("hhh", 1.0, 2.3)));
        g.displayGemoticobject(new Circle("hjhh",1.0,5));
        g.displayGemoticobject(new myreactangle("ss",1.0,2,3));
    }
    public boolean eaualsarea(GeometricObjectr c,GeometricObjectr m){
        if(c.findarea() == m.findarea()){
            return true;
        }else{
            return false;
        }
    }

    public void displayGemoticobject(GeometricObjectr g){
        System.out.println(g.findarea());
    }
}
  • 关于多态的一道面试题目
package com.oop.sgg5.exer7;

public class InterviewTest1 {

    public static void main(String[] args) {
        Base base = new Sub();
        base.add(1, 2, 3);

//		Sub s = (Sub)base;
//		s.add(1,2,3);
    }
}

class Base {
    public void add(int a, int... arr) {
        System.out.println("base");
    }
}

class Sub extends Base {

    public void add(int a, int[] arr) {
        System.out.println("sub_1");
    }

//	public void add(int a, int b, int c) {
//		System.out.println("sub_2");
//	}
}
这里未加注释时,由于Sub类中的add方法使用数组的方式和可变形参所表达的含义相同,因此此时符合重写规则,则在调用中自然构成了重写,输出sub_1,体现多态行为。
当我们加了注释后,由于将base强制转换成了sub类型,此时调用方法时,有限去匹配类中方法体中能匹配到的方法,则此时输出sub_2,这里就是正常的方法调用。

8包装类

在这里插入图片描述
掌握三种主要的转换方法即可

  1. 基本数据类型 --> 包装类
  • 通过构造器 如 Interger f = new Interger(11);
  • 通过字符串参数,如 Float f = new Float(“32.3F”); 或 Long l = new Long(“11”);
  1. 包装类 --> 基本数据类型
  • 调用包装类的方法,xxxValue();
  • 自动拆箱
  1. 基本数据类型 --> String类
  • String类的valueOf(3.4f)方法
  1. String类 --> 基本数据类型
    调用相应的包装类的parseXxx(String)静态方法
  2. 包装类 --> String类
  • 包装类对象的toString()方法。
  • 调用包装类的toString(形参)方法
  1. String类 --> 包装类
    通过字符串参数最合适,Float f = new Float(“32.3F”);

9 Static关键字

Static是静态的,可以用来修饰属性、方法、代码块、内部类

9.1 使用Static修饰属性

  • 属性分为了静态属性和实例变量(非静态属性)。我们创建了多个对象,每个对象拥有一套自己的属性,此时一个对象里属性的改变不会影响到别的对象里的属性,这样的成为实例变量(非静态属性),而静态属性是我们创建了多个对象,此时多个对象共享这个属性,当一个对象对其进行操作后,其他对象使用的时候其属性值是改变的。
  • 三个关于Static修饰属性的点,第一:静态变量随着类的加载而加载,可以通过类名.属性的方法去调用。第二:静态变量的加载是早于实例对象的创建的。第三:静态变量只会加载一次,存在于方法区中,而实例变量随着对象的创建每次都要在堆中重新加载。
  •             类变量          实例变量
     类          yes              no 
    对象         yes              yes
    
  • 静态方法的举例,如我们经常使用的Math.PI

9.2 使用Static修饰方法

  • 随着类的加载而加载,可以通过类.静态方法的方式去进行调用,
    静态方法 非静态方法
    类 yes no
    对象 yes yes
  • 静态方法中,只能调用静态的属性或者方法,非静态方法中,可以调用静态或者非静态的方法或属性。

9.3 关于Static的注意点

  • 在静态方法内,是不可以使用super和this关键字的(有可能对象还未初始化)
  • 关于静态方法以及静态属性可以从生命周期的角度去理解。

9.4 开发中,如何确定一个方法是否要声明为Static

  • 操作静态属性的方法,通常要声明为Static
  • 工具类中的方法,通常也要声明为Static,在使用时可以方便的调用,而不是再去new一个对象

10 代码块

  1. 代码块的作用:用来初始化类和对象
  2. 代码块只能用Static进行修饰,分为静态代码块和非静态代码块
  3. 静态代码块:可以有输出语句,随着类的记载而执行,只执行一次,初始化类的信息。若一个类中定义了多个静态代码块,按照定义的先后顺序进行执行,静态代码块的执行要先于非静态代码块的执行
  4. 非静态代码块:可以有输出语句,随着对象的创建而执行,可执行多次,用来初始化对象的信息。 类中如果定义了多个非静态代码块,则按照定义的先后顺序进行执行。
  5. 对属性可以赋值的位置:默认初始化、显示定义、代码块、构造器、对象.方法或者对象.属性。
  6. 综合执行顺序分析:

11 关于final关键字

  1. final可以用来修饰类、方法、变量
  2. final即“最终”的意思
  3. final修饰类的时候,代表此类不可继承
  4. final修饰方法的时候,代表此方法不可被重写
  5. finla修饰变量,代表两种情况
  • final修饰属性:final修饰属性后,就变成了数值常量,不可以再对常量进行操作或者计算,可以进行初始化的位置有:代码块初始化、构造器初始化、显示初始化。
  • final修饰局部变量:方法体内修饰为final后不可对变量本身再进行计算,如果把方法中国的形参定义为final后,我们就只能在方法体内还有此形参,不可再赋值

12 Abstract关键字

  1. abstract即抽象的
  • abstract只能用来修饰类和方法
  • 抽象类不可以被实例化,只可以被子类继承后实例化子类。但是抽象类中会有构造器,一般供子类对象实例化时使用。
  • 抽象方法只有方法声明没有方法体,子类继承抽象类后需要重写抽象类里的抽象方法,如果没有重写父类中的所有抽象方法,则此子类也是一个抽象类,需要abstract修饰。包含抽象方法的类,一定是一个抽象类,但是抽象类中可以没有抽象方法。
  1. abstract使用中的注意点
  • abstract不能用来修饰,属性、构造器等结构
  • abstract不能用来修饰私有方法、静态方法、final方法、final的类
  1. 理解
  • 抽象方法即是开发中的一种方式,我们首先写出一个拥有较多公共属性和方法的模板类,之后基于不同的场景,定义不同的子类,既能去共享模板类的公共属性和方法,又可以根据自己的特点去重写方法,是一种较好的开发模式。

13 接口

  1. 接口使用Interface来定义,在Java中接口和类是并列的两个结构,
  2. 接口中的成员:
  • 在jdk7之前:只能定义全局常量和抽象方法。全局常量:使用public static final进行修饰,但是可以省略不写,但是不要认为接口中没有定义就是变量了。抽象方法:使用public abstract来进行修饰。
  • 在jdk8之后,还可以定义静态方法和默认方法
  1. 接口中不能定义构造器,意味着接口不可以被实例化
  2. 在Java开发中,接口通过让类去实现(implements)的方式来使用,如果实现类覆盖了接口中的所有抽象方法,则此类可以被实例化。如果实现类没有覆盖接口中的所有抽象方法,那么它仍然是一个抽象类,仍然不可以被实例化。
  3. Java类可以实现多个接口,弥补了单继承性的局限性。class a extends b implements cc,dd,ee
  4. 接口之间也可以继承,继承的结果就是抽象方法共用
  5. 接口也体现了多态性,比如我们把形参定义为接口,而我们在实际使用时,所使用的可能是不同的实现类,这样就具有了很好的通用性。
package com.oop.sgg6.exer6;
interface USB{		//
    public void start() ;
    public void stop() ;
}
//通过使用usb对象作为形参来实现多态
//虽然定义的是usb类型的,但是具体实现的时候传入的是实现类,所使用的方法也是实现类重写后的方法
class Computer{
    public static void show(USB usb){
        usb.start() ;
        System.out.println("=========== USB 设备工作 ========") ;
        usb.stop() ;
    }
}
class Flash implements USB{
    public void start(){	// 重写方法
        System.out.println("U盘开始工作。") ;
    }
    public void stop(){		// 重写方法
        System.out.println("U盘停止工作。") ;
    }
}
class Print implements USB{
    public void start(){	// 重写方法
        System.out.println("打印机开始工作。") ;
    }
    public void stop(){		// 重写方法
        System.out.println("打印机停止工作。") ;
    }
}
public class InterfaceDemo{
    public static void main(String args[]){
        Computer.show(new Flash()) ;
        Computer.show(new Print()) ;

        Computer.show(new USB(){
            public void start(){
                System.out.println("移动硬盘开始运行");
            }
            public void stop(){
                System.out.println("移动硬盘停止运行");
            }
        });
    }
}

此段代码里,先定义一个usb接口,里面含有start和stop方法,之后定义一个computer类其中有静态方法show(),之后u盘和打印机通过实现接口来实现自己的功能,使用computer类的show方法就实现了多态,最后的是使用了一个匿名对象方法实现。

  1. 关于Java8之后的补充:
  • 知识点1:接口中定义的静态方法,只能通过接口来调用
  • 知识点2:通过实现类的对象,可以调用接口中的默认方法
  • 知识点3:类优先原则:如果子类(或实现类)继承的父类实现了和接口中同名同参的方法,那么在子类没有重写此方法的前提下,一般优先调用的是父类中的同名同参的方法。
  • 知识点4:如果在子类或者(实现类)中调用父类、接口中的方法。通常子类调用父类使用的是super关键字,而实现类调接口使用的是接口名.super.方法
  • 知识点5:如果在类继承了多个接口,而这多个接口中定义了同名同参数的默认方法,这会出现接口冲突,报错,这种情况下,我们必须重写方法。
package com.oop.sgg6.exer6;
public class man extends father implements Filial,Spoony{

    public static void main(String[] args) {
        man m = new man();
        m.help();
    }

}
interface Filial {// 孝顺的
    default void help() {
        System.out.println("老妈,我来救你了");
    }
}

interface Spoony {// 痴情的
    default void help() {
        System.out.println("媳妇,别怕,我来了");
    }
}

class father{
    public void help(){
        System.out.println("救wq");
    }
}

此时man类中没有去重写help方法,因此输出:救wq,类优先原则。此时如果自己在man类中重写help方法,则输出的是自己重写之后的方法。

14 内部类

  1. 定义:Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B成为外部类
  2. 内部类的分类:
  • 成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)
  1. 成员内部类的理解:
  • 一方面,作为外部类的成员:可以调用外部的结构,可以被static修饰,可以被4种不同的权限修饰符修饰
  • 另一方面,作为一个类,类内可以定义方法、构造器、属性等,可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承。可以被abstract修饰。
  1. 成员内部类:
    如何创建成员内部类的对象?(静态、非静态的)
    创建静态的Dog内部类实例(静态的成员内部类)
    Person.Dog dog = new Person.Dog();
    创建非静态的Bird内部类实例 (非静态的成员内部类)
    Person p = new Person();
    Person.Bird bird = p.new Bird();
  2. 局部内部类的使用
    一般是一个方法,需要返回一个接口或者实现类,然后在方法中去定义实现类去实现接口。
  3. 注意点:成员内部类和局部内部类,在编译以后,都会生成字节码文件。格式:成员内部类:外部类¥内部类名.class。局部内部类:外部类¥数字 内部类名.class
  4. 在局部内部类的方法中,如果要调用局部内部类所声明的方法中的变量时,则必须声明为final类型的,在JDK7之前需要显示声明,在JDK8之后会自动声明。

15 异常分析

一道综合练习,包括try-catch-finally和throws,以及自定义异常及抛出

package com.oop.sgg6.exer7;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import java.util.Scanner;
/*
编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数,计算
两数相除。
对 数 据 类 型 不 一 致 (NumberFormatException) 、 缺 少 命 令 行 参 数
(ArrayIndexOutOfBoundsException、 除0(ArithmeticException)及输入负数(EcDef 自定义的异常)进行异常处理。
 提示:
(1)在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。
(2)在main()方法中使用异常处理语句进行异常处理。
(3)在程序中,自定义对应输入负数的异常类(EcDef)。
(4)运行时接受参数 java EcmDef 20 10 //args[0]=“20” args[1]=“10”
(5)Interger类的static方法parseInt(String s)将s转换成对应的int值。 如:int a=Interger.parseInt(“314”); //a=314;
 */
public class EcmDef {
    public static int ecm(int a, int b) throws EcDef {
        if (a < 0 || b < 0) {
            throw new EcDef("不能输入负数");
        }
        return a / b;
    }

    public static void main(String[] args) {
        try {
            int i = Integer.parseInt(args[0]);
            int j = Integer.parseInt(args[1]);
            int result = ecm(i, j);
            System.out.println(result);
        } catch (NumberFormatException e) {
            System.out.println("类型不一致");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("缺少命令行参数");
        } catch (ArithmeticException e) {
            System.out.println("除0");
        } catch (EcDef e) {
            System.out.println(e.getMessage());
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值