JaveSE的知识总结

本文详细介绍了Java的基础知识,包括字符串连接、基本类型与引用类型的区别、值传递与引用传递的概念。接着讨论了方法的重载与重写,解释了两者的区别和应用场景。此外,还讲解了流程控制中的`outer`关键字,以及静态方法、构造器、`super`关键字的使用。最后,文章深入探讨了面向对象的特性,如封装、继承和多态,以及异常处理机制,强调了`instanceof`关键字和`finally`块的重要性。
摘要由CSDN通过智能技术生成

JavaSE基础知识

注:在此总结中的知识根据个人的需要记录,一些基础知识并不全面。

一,基础知识

字符串连接符

当输出String+其他类型时,String会将左右两边的类型相连接

System.out.println(""+10+20);
//这里会输出1020

面试题:

请分别判断以下两行代码的运行结果
System.out.println(""+10+20);//这里会输出1020
System.out.println(10+20+"");//输出30

出现上述不同的原因时“”的出现位置,出现在后面的话会先运行10+20;

Java中的基本类型

Java中数据类型分为两大类,基本类型和对象类型。相应的,变量也有两种类型:基本类型和引用类型
基本类型的变量保存原始值,即它代表的值就是数值本身;

而引用类型的变量保存引用值,"引用值"指向内存空间的地址代表了某个对象的引用,而不是对象本身
对象本身存放在这个引用值所表示的地址的位置

基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress,
引用类型包括:类类型,接口类型和数组。

相应的,变量也有两种类型:基本类型和引用类型。

变量的基本类型和引用类型的区别

(1)基本数据类型在声明时系统就给它分配空间:

int a;
a=10;//正确,因为声明a时就分配了空间

(2)引用型声明时只给变量分配了引用空间,而不分配数据空间:

Date date;
//执行实例化,开辟数据空间存放Date对象,然后把空间的首地址传给today变量 
//date=new Date();
//如果注释掉上一步操作,也就是说对象的数据空间没有分配

看一下下面的初始化过程,注意"引用"也是占用空间的,一个空Object对象的引用大小大概是4byte

Date a,b; ``//在内存开辟两个引用空间
a = ``new` `Date();``//开辟存储Date对象的数据空间,并把该空间的首地址赋给a
b = a; ``//将a存储空间中的地址写到b的存储空间中
引用传递和值传递

值传递:

方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数后面方法中的操作都是对形参这个值的修改,不影响实际参数的值

引用传递:

也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;
**在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中*对引用的操作*将会影响到实际对象

请看如下例子:

package Mao.Learning;
class node{
    int val = 10;
}
public class Demo07 {
    public static void main (String[] args) {
        int a = 10;
        test1(a);
        System.out.println("在值传递中,main函数的a的值为"+a);

        node node  = new node();
        test2(node);
        System.out.println("在引用传递中,main函数的node.val的值为"+node.val);
    }

    private static void test2 (node node) {

        node.val = 20;
        System.out.println("在引用传递中,方法函数的node.val的值为"+node.val);

    }

    private static void test1 (int a) {

        a = a+10;
        System.out.println("在值传递中,方法函数的a的值为"+a);
    }
}

运行之后的结果为:

在值传递中,方法函数的a的值为20
在值传递中,main函数的a的值为10
在引用传递中,方法函数的node.val的值为20
在引用传递中,main函数的node.val的值为20

为什么会出现这种情况呢?

因为在值传递中,我们可以将方法中的变量理解为临时变量,也就是说此时共有两个变量,即main函数中的变量和方法中的临时变量。我们修改的只是是方法中的临时变量。

而在引用传递中,我们传入的是实际变量的的地址,也就是说在方法函数中修改的是实际变量的val,所以当主函数调用实际变量时,该变量的val已经发生变化。

这里要注意,String类型由于无法修改,每次都是新生成对象,所以和值传递类似。

二,流程控制

Outer

outer用于退出当前循环跳到指定位置,类似goto;

        //打印10-30内所有的质数
        outer:for (int i = 10;i<=30;i++){
            for (int j = 2;j<i/2;j++){
                if (i % j == 0){

                    continue outer;
                }
            }
            System.out.print(i+" ");
        }

三,方法

方法的参数有实参和形参,实参是调用时传入的数值,形参是方法体定义的。如对于方法

int sum  = add(1,2);//这里的1和2就是实参
public int add(int a ,int b){};//此处的a,b即为形参
方法的重写:

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法

方法的重写规则:
  • 参数列表与被重写方法的参数列表必须完全相同。
  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
  • 父类的成员方法只能被它的子类重写。
  • 声明为 final 的方法不能被重写。
  • 声明为 static 的方法不能被重写,但是能够被再次声明。
  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
  • 构造方法不能被重写。
  • 如果不能继承一个类,则不能重写该类的方法。

方法的重写请参考如下代码:(来自网络)

class Animal{
   public void move(){
      System.out.println("动物可以移动");
   }
}
 
class Dog extends Animal{
   public void move(){
      System.out.println("狗可以跑和走");
   }
}
public class TestDog{
   public static void main(String args[]){
      Animal a = new Animal(); // Animal 对象
      Animal b = new Dog(); // Dog 对象
 
      a.move();// 执行 Animal 类的方法
 
      b.move();//执行 Dog 类的方法
   }
}

运行结果:
动物可以移动
狗可以跑和走    
Super关键字:

当需要在子类中调用父类的被重写方法时,要使用 super 关键字。

请参考以下代码:

class Animal{
   public void move(){
      System.out.println("动物可以移动");
   }
}
 
class Dog extends Animal{
   public void move(){
      super.move(); // 应用super类的方法
      System.out.println("狗可以跑和走");
   }
}
 
public class TestDog{
   public static void main(String args[]){
 
      Animal b = new Dog(); // Dog 对象
      b.move(); //执行 Dog类的方法
 
   }
}

//代码运行结果如下
//动物可以移动
//狗可以跑和走
方法的重载:

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同

每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。

最常用的地方就是构造器的重载。

重载的重载规则:
  • 被重载的方法必须改变参数列表(参数个数或类型不一样);
  • 被重载的方法可以改变返回类型;
  • 被重载的方法可以改变访问修饰符;
  • 被重载的方法可以声明新的或更广的检查异常;
  • 方法能够在同一个类中或者在一个子类中被重载。
  • 无法以返回值类型作为重载函数的区分标准。
重写与重载之间的区别
区别点重载方法重写方法
参数列表必须修改一定不能修改
返回类型可以修改一定不能修改
异常可以修改可以减少或删除,一定不能抛出新的或者更广的异常
访问可以修改一定不能做更严格的限制(可以降低限制)
静态方法:

如果一个类要被声明为static的,只有一种情况,就是静态内部类。

静态方法不需要通过它所属的类的任何实例就可以被调用,因此在静态方法中不能使用this关键字,也不能直接访问所属类的实例变量和实例方法,但是可以直接访问所属类的静态变量和静态方法。

在Java中,静态方法是和类一起加载的,普通方法是类实例化之后才存在的。如何理解这句话呢,请看以下例子:

    //在java类中,以下方法调用方式是合法的,因为两者都是普通的方法,可以互相调用
    public void a(){ b() ; };
    public void b(){       };

    //在java类中,以下方法调用方式是合法的,因为两者都是静态的方法,可以互相调用
    public static void a(){ b() ; };
    public static void b(){       };

    //在java类中,以下方法调用方式是不合法的,因为静态方法a()是和类一起加载的,而普通方法b是
    //在创建实例化对象后创建的。一个方法无法调用未创建的方法
    public static void a(){ b() ; };
    public  void b(){       };


总结

方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

  • (1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
  • (2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
  • (3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

四,面向对象

面向对象的基本概念:

面向对象的本质就是:以类的方式组织代码,以对象的组织(封装)数据。

三大特性: 封装,继承,多态

类和对象

类是一种抽象的数据类型,它是对某一类事务的整体描述。如 class person 就是抽象人这个类。

对象是类的具体实例。如 person Mike = new person();这里的Mike就是具体的一个对象。

注意:在 person Mike = new person()这句语句中,Mike 是变量名,存在栈中。而真正的对象在堆中.

封装

封装的意义:

(1)提高程序的安全性,保护数据

(2)隐藏代码的实现细节

(3)统一接口

(4)提高系统的可维护性

private 私有关键词,当给一个属性为私有属性是,无法直接调用和 改变。

操作属性的方法 get(),set();

继承

复用代码是Java众多引人注目的功能之一。

继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。

继承的特点:

1、子类拥有父类非private的属性和方法。

2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。

3、子类可以用自己的方式实现父类的方法。

构造器

子类可以继承父类的属性和方法,除了那些private的外还有一样是子类继承不了的—构造器。对于构造器而言,它只能够被调用,而不能被继承。 调用父类的构造方法我们使用super()即可。

对于子类而已,其构造器的正确初始化是非常重要的,而且当且仅当只有一个方法可以保证这点:在构造器中调用父类构造器来完成初始化,而父类构造器具有执行父类初始化所需要的所有知识和能力。

public class Person {
    protected String name;
    protected int age;
    protected String sex;
    
    Person(){
        System.out.println("Person Constrctor...");
    }
}

public class Husband extends Person{
    private Wife wife;

    Husband(){
        System.out.println("Husband Constructor...");
    }
    
    public static void main(String[] args) {
        Husband husband  = new Husband();
    }
}

Output:
Person Constrctor...
Husband Constructor...
(代码来自网络)

通过以上的示例可以看出,其实在子类的构造器中隐藏了一个super();但是这里要注意这种情况是需要父类有默认构造器的条件,**如果父类没有构造器,我们就必须加上一个和super()**来调动父类构造器,而且必须是在子类构造器中第一行代码,否则就会报错。

protected关键字

对于protected而言,它指明就类用户而言,他是private,但是对于任何继承与此类的子类而言或者其他任何位于同一个包的类而言,他却是可以访问的。

public class Person {
    private String name;
    private int age;
    private String sex;

    protected String getName() {
        return name;
    }

    protected void setName(String name) {
        this.name = name;
    }

    public String toString(){
        return "this name is " + name;
    }
    
    /** 省略其他setter、getter方法 **/
}

public class Husband extends Person{
    private Wife wife;

    public  String toString(){
        setName("chenssy");    //调用父类的setName();
        return  super.toString();    //调用父类的toString()方法
    }

    public static void main(String[] args) {
        Husband husband = new Husband();
        
        System.out.println(husband.toString());
    }
}

Outputthis name is chenssy

从上面示例可以看书子类Husband可以明显地调用父类Person的setName()。

Java 向上转型和向下转型

父子对象之间的转换分为了向上转型向下转型,它们区别如下:

  • 向上转型 : 通过子类对象(小范围)实例化父类对象(大范围),这种属于自动转换
  • 向下转型 : 通过父类对象(大范围)实例化子类对象(小范围),这种属于强制转换
public class Demo02 {
    public static void main (String[] args) {

        Person person = new Student();//这里创造的实际是Person对象的引用
        person.say();

    }
}
class Person{
    public void say(){
        System.out.println("I am Person ");
    }
}
class Student extends Person{
    public void say(){
        System.out.println("I am Student ");
    }
}

为什么要向上转型呢?向上转型的意义在于当我们需要多个同父的对象调用某个方法时,通过向上转换后,则可以确定参数的统一.方便程序设计

多态

不同类的对象对同一消息作出不同的响应就叫做多态

请分析以下代码:

public class Demo02 {
    public static void main (String[] args) {

        Person person = new Student();//这里创造的实际是Person对象的引用
        person.say();

    }
}
class Person{

}
class Student extends Person{
    public void say(){
        System.out.println("I am Student ");
    }
}

运行以上代码,会发现无法运行。这是由于父类的Peroson中没有say()方法,在java中父类型可以指向子类型,但是无法调用子类型的独有方法。

一个对象能执行哪些方法,主要看对象左边的类型,和右边关系不大 。如下

Person person = new Student();//创造了一个Person,指向子类型Student,只能调用Person的方法。
多态存在的三个条件

1、有继承关系

2、子类重写父类方法

3、父类引用指向子类对象

无法使用多态的关键字

1、static方法,因为被static修饰的方法是属于类的,而不是属于实例的

2、final方法,因为被final修饰的方法无法被子类重写

3、private方法和protected方法,前者是因为被private修饰的方法对子类不可见,后者是因为尽管被protected修饰的方法可以被子类见到,也可以被子类重写,但是它是无法被外部所引用的,一个不能被外部引用的方法,怎么能谈多态呢

多态的分类

1、编译时多态,即方法的重载,从JVM的角度来讲,这是一种静态分派(static dispatch)

2、运行时多态,即方法的重写,从JVM的角度来讲,这是一种动态分派(dynamic dispatch)

instanceof 关键字

A instanceof B A是否为B的子类型 返回True或者False;

注意:子类转化为父类可能会丢失一些方法。

static修饰符

static静态代码块:和类同时加载,一般用于初始化,只会执行一次。

请参考一下以下案例:

public class Demo12 {

    {
        System.out.println("匿名代码块");

    }

    static {
        System.out.println("静态代码块");//只会输出一次
    }

     Demo12(){
         System.out.println("构造器");
     }

    public static void main (String[] args) {
        new Demo12();
        new Demo12();
    }
}

输出:
静态代码块
匿名代码块
构造器
匿名代码块
构造器

**final类无法被继承。**如Math;

抽象类abstract

抽象类的意义是为了更好的将设计与实现分离。

抽象类里有抽象方法,抽象方法只声明无需写代码体。无法new抽象类的实际对象。

抽象类的子类若非抽象类,那么必须实现其父类的所有方法。

抽象类里可以有普通方法,抽象方法必须写在抽象类中。

接口interface

接口的本质是契约,接口只有规范,自己无法写方法,实现约束和实现分离:面向接口编程

接口中默认的方法都是public abstract,接口中定义的属性是都默认常量。

子类实现接口使用implements关键字。

五,异常Exception

异常本质上是程序上的错误,包括程序逻辑错误和系统错误。比如使用空的引用、数组下标越界、内存溢出错误等,这些都是意外的情况,背离我们程序本身的意图。错误在我们编写程序的过程中会经常发生,包括编译期间和运行期间的错误,在编译期间出现的错误有编译器帮助我们一起修正,然而运行期间的错误便不是编译器力所能及了,并且运行期间的错误往往是难以预料的。假若程序在运行期间出现了错误,如果置之不理,程序便会终止或直接导致系统崩溃,显然这不是我们希望看到的结果。因此,如何对运行期间出现的错误进行处理和补救呢?Java提供了异常机制来进行处理,通过异常机制来处理程序运行期间出现的错误。通过异常机制,我们可以更好地提升程序的健壮性。

异常的结构图

img

根据以上的图,我们可以看出:

1,在Java中异常被当做对象来处理,根类是java.lang.Throwable类,在Java中定义了很多异常类(如OutOfMemoryError、NullPointerException、IndexOutOfBoundsException等),这些异常类分为两大类:Error和Exception。

2,Error是无法处理的异常,比如OutOfMemoryError,一般发生这种异常,JVM会选择终止程序。因此我们编写程序时不需要关心这类异常。

3,Exception,也就是我们经常见到的一些异常情况,比如NullPointerException、IndexOutOfBoundsException,这些异常是我们可以处理的异常。

处理异常

Java中如果需要处理异常,必须先对异常进行捕获,然后再对异常情况进行处理

try {
  File file = new File("d:/a.txt");
  if(!file.exists())
    file.createNewFile();
} catch (IOException e) {
 
}

被try块包围的代码说明这段代码可能会发生异常,一旦发生异常,异常便会被catch捕获到,然后需要在catch块中进行异常处理。

这是一种处理异常的方式。在Java中还提供了另一种异常处理方式即抛出异常,顾名思义,也就是说一旦发生异常,我把这个异常抛出去,让调用者去进行处理,自己不进行具体的处理,此时需要用到throw和throws关键字。

public class Main {
    public static void main(String[] args) {
        try {
            createFile();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
     
    public static void createFile() throws IOException{
        File file = new File("d:/a.txt");
        if(!file.exists())
            file.createNewFile();
    }
}

这段代码和上面一段代码的区别是,在实际的createFile方法中并没有捕获异常,而是用throws关键字声明抛出异常,即告知这个方法的调用者此方法可能会抛出IOException。那么在main方法中调用createFile方法的时候,采用try…catch块进行了异常捕获处理。

当然还可以采用throw关键字手动来抛出异常对象。下面看一个例子:

public class Main {
    public static void main(String[] args) {
        try {
            int[] data = new int[]{1,2,3};
            System.out.println(getDataByIndex(-1,data));
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
         
    }
     
    public static int getDataByIndex(int index,int[] data) {
        if(index<0||index>=data.length)
            throw new ArrayIndexOutOfBoundsException("数组下标越界");
        return data[index];
    }
}

然后在catch块中进行捕获。

异常的处理顺序为try—>catch—>finally。

在有多个catch块的时候,是按照catch块的先后顺序进行匹配的,一旦异常类型被一个catch块匹配,则不会与后面的catch块进行匹配。

在使用try…catch…finally块的时候,注意千万不要在finally块中使用return,因为finally中的return会覆盖已有的返回值。

父类的方法没有声明异常,子类在重写该方法的时候不能声明异常;

如果父类的方法声明一个异常exception1,则子类在重写该方法的时候声明的异常不能是exception1的父类;

注:部分资料来自网络。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小黑mmd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值