java基础部分-第二周学习总结

多态

定义:

多态指的是同一个方法调用在不同对象上会产生不同的行为。在Java中,多态是通过继承,接口和重写实现的。

实现多态:

多态的实现依赖于继承和重写(或许实现接口),子类重写(或实现接口)父类的方法,从而实现了同一方法在不同类对象上的不同行为。

重载是在同一个类中,方法名相同但参数不同;

重写是在子类中,方法名,参数和返回值都与父类中的方法完全相同,方法进行的操作可以不相同。

在多态中,通过父类类型的引用变量调用的方法,实际上是在运行时根据对象的实际类型来确定调用哪个类中的方法。

这样可以提高代码灵活性和扩展性,使得程序更易于维护和扩展。

向上转型和向下转型

向上转型(upcasting)是指子类的实例可以被赋值给父类类型的引用变量,向上转型是安全的,子类实例拥有父类的所有特征

向下转型(downcasting)是指将父类类型的引用变量转换为子类类型的引用变量,向下转型可能会引发类型转换异常,因为子类类型的引用变量可能无法访问父类中不存在的属性或方法。

public abstract class Test1 {
    public int a;
    public int b;

    public void xie(){
        System.out.println("写");
    }

    public abstract void eat();

}
public class Test2 extends Test1{
    @Override
    public void eat() {
        System.out.println("吃");
    }

    public void tiao(){
        System.out.println("跳");
    }

}
public class Test {
    public static void main(String[] args) {
        Test1 test1 = new Test2();//向上转型,子类的实例赋值给父类类型的引用变量
        test1.eat();
        test1.xie();

        Test2 test2 = (Test2) test1;//向下转型
        test2.tiao();
        test2.xie();
        test2.eat();

    }
}

优点:

多态提高了代码的扩展性和复用性,使程序更易理解和维护。同时,多态能提高程序设计的灵活性,使系统更易于扩展和改变。

instanceof关键字

“instanceof” 是Java中的一个二元操作符,用来测试一个对象是否为一个类的实例,也用于测试一个对象是否为一个接口的实现类的实例。

语法格式如下:

object instanceof ClassName

其中,object 是一个对象实例,ClassName 是一个类名或接口名。

“instanceof” 关键字返回一个布尔值。如果 object 是 ClassName 的一个实例,那么结果为 true;否则为 false。

这个关键字在处理类似向下转型的情况时特别有用,可以避免类型转换错误。比如,在多态的情况下,一个父类引用可能实际引用了一个子类对象,这时如果直接将该引用转为子类类型可能会出错,可以先用 “instanceof” 来检查一下。

示例:

class A {}
class B extends A {}

A obj1 = new A();
B obj2 = new B();

System.out.println(obj1 instanceof A); // 输出 true
System.out.println(obj2 instanceof A); // 输出 true,因为 B 继承了 A
System.out.println(obj2 instanceof B); // 输出 true
System.out.println(obj1 instanceof B); // 输出 false

同样地,可以用于判断一个对象是否实现了某个接口:

interface MyInterface {}

class MyClass implements MyInterface {}

MyClass obj = new MyClass();

System.out.println(obj instanceof MyInterface); // 输出 true

接口

接口(interface)是Java中一种引用类型,用于定义一组抽象方法的集合,但不包含方法的具体实现。接口可以被理解为一种规范或者是一种契约,它定义了一批方法,规定了具体实现这些方法的类应当具备的行为。

定义接口:接口使用关键字interface进行定义。比如定义一个可飞翔的接口:

public interface Flyable {
    void fly();
}

实现接口:类可以使用关键字implements来实现接口,从而继承接口的抽象方法。一个类可以实现多个接口。

public class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("Bird can fly.");
    }
}

接口的继承:和类一样,接口也可以继承其他接口,可以使用extends关键字。

interface A {
    void a();
}

interface B extends A {
    void b();
}

方法定义

接口中的方法默认是public和abstract的,说明它们必须在接口的实现类中被实现。

返回值类型 方法名(参数列表);
void getName();
省略了 public abstract
public abstract void getName();

细节:接口是一种抽象的概念,它只能包含抽象方法的声明,而不能包含具体的方法实现或构造方法。因此,接口中不能定义构造方法。

属性定义

接口的属性默认是 public、static、final 类型,即为公有的静态常量。这些属性会在所有实现该接口的类中共享。也就是说,我们不能在接口的实现类中改变这些属性的值。

数据类型 属性名;//public static final都可以省略

public interface TestInterface {
    int CONSTANT = 100;  // public static final都可以省略
}

在这个示例中,接口TestInterface定义了一个常量 CONSTANT,即便我们没有明确给出 “public static final”,它也会被Java编译器自动添加上,所以这个常量是公有的、静态的、不可修改的。

接口无法定义构造方法,因为接口是不能被实例化的,也就无法调用构造方法。接口是被其实现类实例化的,实现类在实例化的时候会调用自己的构造方法。接口主要是用于规定实现类必须遵守的规则(要实现的方法)。

体现原则:

  1. 抽象原则(Abstraction): 接口定义了一组抽象方法,而不包含具体实现。这样可以将接口与具体实现分离,使得代码更易于理解和维护。
  2. 多态原则(Polymorphism): 通过接口,不同的类可以实现相同的接口,并提供自己的具体实现。这样,可以使用接口类型的引用变量来引用不同类的对象,并调用相同的方法,实现了同一方法在不同类对象上的多态行为。

面试题:

一个类可以继承类或者实现接口来完成相同的功能,那么两者的区别是什么?

继承使得子类具有父类相同的属性和方法。并能对其进行扩展和重写

实现接口只是实现了接口定义的功能规定,不包括任何实现代码和数据

异常

定义:

异常情况是指程序在运行时,可能由与外部系统的条件变更(与我们一厢情愿所设想的不一设)而导致程序可能会出错的情况。

如我们的代码要连结数据库,但数据库未启动,要创建目录,操作系统上却己存在同名的真实文件;即所谓异常是指可能(仅是可能)由与外部系统的,导致程序可能出错(中断运行)的原因。

代码如下:

import java.util.Scanner;

/**
 * 演示除数为0的情况
 * @author pactera
 *
 */
public class TestException {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入被除数:");
		int num1 = input.nextInt();
		System.out.println("请输入除数:");
		int num2 = input.nextInt();
		System.out.println("计算结果如下:");
		System.out.println(num1+"/"+num2+"="+(num1/num2));
	}
}

当我们除数不是0的时候,程序是正常执行的:

在这里插入图片描述

但是当我们的除数输入的是0,程序就会出现错误,也就是我们说的异常:

在这里插入图片描述

异常的体系结构

​ java为我们提供了非常完美的异常处理机制,使得我们可以更加专心于我们的程序,在使用异常之前我们需要了解它的体系结构:
在这里插入图片描述

从上面这幅图可以看出,Throwable是java语言中所有错误和异常的超类(万物即可抛)。它有两个子类:ErrorException
	其中Error为错误,是程序无法处理的,如OutOfMemoryError、ThreadDeath等,出现这种情况你唯一能做的就是听之任之,交由JVM来处理,不过JVM在大多数情况下会选择终止线程。

 而Exception是程序可以处理的异常。它又分为两种CheckedException(受捡异常),一种是UncheckedException(不受检异常)。其中CheckException发生在编译阶段,必须要使用try…catch(或者throws)否则编译不通过。而UncheckedException发生在运行期,具有不确定性,主要是由于程序的逻辑问题所引起的,难以排查,我们一般都需要纵观全局才能够发现这类的异常错误,所以在程序设计中我们需要认真考虑,好好写代码,尽量处理异常,即使产生了异常,也能尽量保证程序朝着有利方向发展。
优雅的异常处理

​ Java具有代码级的强制性异常检测机制,即许多常见的可预料的异常可能都必须编写代码处理,否则就无法编译通过。

try-catch

try指“尝试”执行可能出现异常的代码,如果成功,则乎略备用方案,即(B)区的代码;但如失败,代码会catch(捕获)到一个异常对象,放弃(A)计划,开始执行(B)计划!

try{
可能抛出异常的代码. . .
//如果没有问题出理,执行如下面的代码
(A)其它计算代码…
}catch(Exception ef){
  //如果出现异常后执行的代码:
(B)出了异常情况的计算代码. . .
}
	try catch结构的异常处理提供了这样一种机制:如果代码执行成功,程序流程正常,
	(B)块的代码将不会执行;如果执行时(A)代码前的语句出现异常,
	(A)代码将不会执行,程序跳转到(B)代码块开始执行,
	同时,可(B)代码块中可以得到Exception类型变量ef对这个异常对象的引用,可以调用ef. printStackTrace();
	方法打印出异常的详细细信息;这为程序从错误中恢复提供了可行的手段。
import java.util.Scanner;

/**
 * 演示除数为0的情况
 * @author pactera
 *
 */
public class TestException {
	public static void main(String[] args) {
		try{//放的是可能会出现异常的代码
			Scanner input = new Scanner(System.in);
			System.out.println("请输入被除数:");
			int num1 = input.nextInt();
			System.out.println("请输入除数:");
			int num2 = input.nextInt();
			System.out.println("计算结果如下:");
			System.out.println(num1+"/"+num2+"="+(num1/num2));
            System.out.println("========程序结束!!!!=============");
		}catch(ArithmeticException e){ //catch是捕获异常,并进行处理
			//需要注意,我们这个catch捕获的只能是ArithmeticException异常或者其子类异常,对其他异常不捕获
			e.printStackTrace();//可以在控制台打印详细的异常信息,在开发阶段使用,便于调试代码
//异常的处理,我们简单输出一句话,但是在真实的项目中,不能只是输出一句话,而是要做相应的处理
			System.out.println("你丫的没读过小学吗?不知道除数不能为0吗");
		}
       System.out.println("============程序结束!!!!==================");
	}
}

代码运行情况:

  • 第一种情况,当程序正常执行,try中的代码执行完,catch中的代码不会执行,catch后面的代码会执行

在这里插入图片描述

  • 第二种情况,当程序发生异常,并且异常的类型与catch小括号的异常一样,try中发生异常处之后的代码不会执行,则执行catch中的代码,catch后的代码也会执行.

在这里插入图片描述

  • 第三种情况,当程序发生异常, 并且异常的类型与catch小括号的异常不一样, try中发生异常处之后的代码不会执行,也不执行catch中的代码,catch后的代码也不执行.程序会在发生异常区终止程序.
    在这里插入图片描述

需要注意的是:

  1. try catch块中变量做用域:try块中定义的变量符合我们前面所讲的变量做用范围的规则,即变量只能在限定自己最近的一对大括号内使用;即try catch块内一对大括号中定义的变量不能在后面的代码块内使用;
  2. 方法返回值:如果方法有定义的返回值,这个方法就有可以在正常执行时有一个返回值,或在catch到异常时有个返回值—不能仅仅只在try块中return一个返回值。
try-catch-finally

finally段的代码无论是否发生异常都执行

try{

}catch(Exception e){
	
}finally{//不管是否异常都会执行

}
throw 与throws

throw表示抛出异常,语法是:

throw new 异常类型([异常信息]);

比如说: throw new Exception(“抛个异常玩玩”);

throws表示用来声明方法可能会抛出那些异常: 语法是:

throws 异常类型1,异常类型2

代码演示:

//定义一个除法的方法,并声明异常
	public int division(int num1 ,int num2) throws ArithmeticException{
		if(num2 == 0){
			//抛出异常,如果抛出异常,则抛出异常后面的代码不会执行
			throw new ArithmeticException("除数不能为0");
		}
		return num1/num2;
	}
自定义异常

创建异常类

创建自定义异常,需要继承Exception 或其子类。习惯上包装一下父类的构造方法。

public class MyException extends Exception {
    public MyException() {
        super();
    }
    public MyException(String msg) {
        super(msg);
    }
    public MyException(Throwable cause) {
        super(cause);
    }
    public MyException(String msg, Throwable cause) {
        super(msg, cause);
    }
}

使用自定义异常类

public String[] createArray(int length) throws MyException {
    if (length < 0) {
        throw new MyException("数组长度小于0,不合法");
    }
    return new String[length];
}

常用类

基本数据类型包装类

​ Java是一种纯面向对象语言,但是java中有8种基本数据类型,破坏了java为纯面向对象的特征。为了承诺在java中一切皆对象,java又给每种基本数据类型分别匹配了一个类,这个类我们称之为包装类。

注意:每个基本数据类型都有一个与之匹配的包装类。

八大基本数据类型的包装类

在这里插入图片描述

注意:int的包装类的写法为Integer、char的包装类的写法是:Character

其余基本数据类型的包装类均是基本类型的首字母大写。

包装类的层次结构

在这里插入图片描述

包装类中的常用方法

装箱:把基本数据类型包装为对应的包装类对象

1、 Integer i1 = new Integer(10); // 利用构造方法

2、 Integer i2 = Integer.valueOf(10); //利用包装类中的静态方法

拆箱:把包装类对象转换为对应的基本数据类型。

1、int i3= i1.intValue(); //返回包装类对象i1对应的基本数据

public class NumberWrap {
public static void main(String[] args) {
  String str = args[0];
  //------------- String转换成Integer
  Integer integer = new Integer(str);     // 方式一
  // Integer integer = Integer.valueOf(str); //方式二
  //------------- Ingeter转换成String
  String str2 = integer.toString(); 
  //------------- 把integer转换成int 
  int i = integer.intValue();
  //------------- 把int转换成Integer
  Integer integer2 = new Integer(i);//
  //Integer integer2 = Integer.valueOf(i); 
  //------------- String转换成int 
  int i2 = Integer.parseInt(str);
  //------------- 把int转换成String
  String str3 = String.valueOf(i2);  // 方式一
  String str4 = i2 + "";   // 方式二
}

其他方法比如:

在这里插入图片描述

System.out.println(Integer.toBinaryString(5));//00000101
System.out.println(Integer.toHexString(15));//f
System.out.println(Integer.toOctalString(9));//11
char c = 'a';
//判断是否是一个数字
System.out.println(Character.isDigit(c));//false
自动装箱和自动拆箱

前面的装箱和拆箱操作,相对较麻烦。自jdk1.5开始,java增加的对基本数据类型的自动装箱和自动拆箱操作。

​ java编译器在编译时期会根据源代码的语法来决定是否进行装箱或拆箱。

1、 自动装箱:可以直接把一个基本数据类型赋值给包装类

例如: Double d = 3.3; //自动装箱操作

2、 自动拆箱:可以直接把一个包装类对象,赋值给基本类型

例如:int a = new Integer(3); //自动拆箱。

自动装箱和自动拆箱,简化了对包装类的操作。

字符串相关类

字符串的实例化

字符串的两种实例化方式及其差别

​ 1).String str = “abc”;

​ 2).String str = new String(“abc”);

Java运行时会维护一个String Pool(String池), 也叫“字符串区”。String池用来存放运行时中产生的各种字符串,并且池中的字符串的内容不重复。而一般对象不存在这个缓冲池,并且创建的对象仅仅存在于方法的堆栈区。

String对象的创建很讲究需要注意的点如下:

​ a.当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个s在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加

​ b.Java中,只要使用new关键字来创建对象,则一定会(在堆区)创建一个新的对象

​ c.使用直接指定或者使用纯字符串串联来创建String对象,两个或者两个以上的字符串常量直接相加,在预编译的时候 “+” 会被优化,自动拼接成一个.则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。

​ d.使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。最后指向堆内存中的对象

​ 对于字符串变量的相加(s1 + s2),本质上是先创建 new StringBuilder(),调用 append 方法进行拼接,最后调用 toString(),实际上还是 new String()

public class StringTest {
	public static void main(String args[]) {
		// 在池中和堆中分别创建String对象"abc",s1指向堆中对象
		String s1 = new String("abc");
		// s2直接指向池中对象"abc"
		String s2 = "abc";
		// 在堆中为"abc"创建新对象,s3指向该对象
		String s3 = new String("abc");
		// 在池中创建对象"ab" 和 "c",并且s4指向池中对象"abc"
		String s4 = "ab" + "c";
		// c指向池中对象"c"
		String c = "c";
		// 在堆中创建新的对象"abc",并且s5指向该对象
		String s5 = "ab" + c;

		System.out.println("------------实串-----------");
		System.out.println(s1 == s2); // false
		System.out.println(s1 == s3); // false
		System.out.println(s2 == s3); // false
		System.out.println(s2 == s4); // true
		System.out.println(s2 == s5); // false
	}
}

请解释String对象的两种实例化方式的区别?

· String对象的实例化方式有两种:一种是直接赋值,另外一种是通过构造方法完成;

· 直接赋值:只开辟一个堆内存空间,而且采用了共享设计模式,可以自动的入池,以备下次对象继续使用;

· 构造方法:会开辟两块内存空间,其中有一块空间将成为垃圾,而且不会自动入池,但是可以使用intern()方法进行手工入池;

·从开发角度而言,很明显使用直接赋值的方式会更好一些。

String的匿名对象

双引号引起来的一个字符串常量就是一个String的匿名对象, 字符串常量

例如 “abc”

字符串的运算

字符串类型的数据与其他数据类型做运算时,结果一定是字符串类型

例如:

	String s3 = “abc” + “d”;

	String s4 = s3 + 5;  //abcd5

字符串的比较

  • ”==”表示判断该两个字符串是否为同一对象,即在内存中的地址是否一样。如果一样则返回true 否则返回false; 和我们通常的是否为同一对象的是一样的。

  • **boolean equals(ObjectanObject) 将此字符串与指定的对象比较。**注意此时比较的是内容是否相等(字符串类对此方法进行了覆写)。

  • int compareTo(Stringvalue) 按字典顺序比较两个字符串。如果两个字符串相等,则返回0;如果字符串在参数值之前,则返回值小于 0;如果字符串在参数值之后,则返回值大于 0

  • int compareToIgnoreCase(String val) 按字典顺序比较两个字符串,不考虑大小写

  • boolean startsWith(String value) 检查一个字符串是否以参数字符串开始。

  • boolean endsWith(String value) 检查一个字符串是否以参数个字符串结束。

字符串的不可改变

字符串的内容一旦申明,就不能被改变

做类似于+=的操作后,实际上是指向了新的地址,原来的空间里面的内容还是没有改变

如果字符串内容经常发生改变,建议使用StringBuffer

字符串的常用方法

1.字符与字符串:
public String(char[] value)--------------------------全部字符数组变为String类
public String(char[] value,int offset,int count)-----部分字符数组变为String
public char charAt(int index)------------------------返回指定位置上的字符
public char[] toCharArray()--------------------------字符串变为字符数组
2.字节数组与字符串:
public String(byte[] bytes)--------------------------全部字节数组变为字符串
public String(byte[] bytes,int offset,int length)----部分字节数组变为字符串
public byte[] getBytes()-----------------------------字符串变为字节数组
public byte[] getBytes(String charsetName)throws UnsupportedEncodingException-----------------转码
3.字符串比较:
public boolean equals(String anObject)---------------字符串内容的比较,区分大小写
public boolean equalsIgnoreCase(String anotherString)不区分大小写完成字符串内容的比较
public int compareTo(String anotherString)-----------判断字符串的大于,小于,等于
4.字符索引:
public boolean contains(String s)--------------------判断指定的子字符串是否存在
public int indexOf(String str)-----------------------从头查找指定的子字符串是否存在,存在则返回字符串的索引,不存在则返回-1
public int indexOf(String str,int fromIndex)---------从指定位置开始检索,没找到则返回-1
public int lastIndexOf(String str)-------------------从后向前查找字符串的位置
public int lastIndexOf(String str,int fromIndex)-----从指定位置开始由后向前查找
public boolean startsWith(String prefix)-------------判断是否以指定字符串开头
public boolean endsWith(Sting suffix)----------------判断是否以指定字符串结尾
5.字符串替换:
public String replaceAll(String regex,String replacement)满足条件的内容全部替换
public String replaceFirst(String regex,String replacement)替换第一个满足条件的内容
6.字符串截取:
public String subString(int beginindex)--------------从头截取到尾
public String subString(int beginindex,int endindex)-截取中间的部分内容
7.字符串拆分:
public String[] split(String regex)------------------全拆分
public String[] split(String regex,int limit)--------拆分成指定的个数
8.其他方法:
public boolean isEmpty()-----------------------------判断是否是空字符串,不是null
public int length()----------------------------------取得字符串内容的长度
public String toLowerCase()--------------------------所有内容变为小写
public String toUpperCase()--------------------------所有内容变为大写
public String trim()--------------------------------去掉左右空格,中间的无法去掉

StringBuffer类

为什么使用StringBuffer类

字符串的不变性:

  1. 一个String对象的长度是固定的,不能改变它的内容,或者是附加新的字符到String对象中。
  2. 您也许会使用+来串联字符串以达到附加新字符或字符串的目的,但+会产生一个新的String对象。
  3. 如果程序对这种附加字符串的需求很频繁,系统会频繁在内存中创建String对象,造成性能下降。所以并不建议使用+来进行频繁的字符串串联。应该使用java.lang.StringBuffer类。

StringBuffer的使用

长度经常变化的字符串,可以考虑使用StringBuffer

//建议长度经常变化的字符串,采用StringBuffer

StringBuffer buffer = newStringBuffer();

buffer.append(“hello”);

buffer.append(“world”);

StringBuffer和StringBuilder

StringBuilder与StringBuffer的用法完全一致,唯一的区别是StringBuffer是线程安全的,而StringBuilder不是线程安全的。所以StringBuilder的性能要比StringBuffer要好。

单线程推荐使用StringBuilder,多线程使用StringBuffer。
lic String subString(int beginindex,int endindex)-截取中间的部分内容
7.字符串拆分:
public String[] split(String regex)------------------全拆分
public String[] split(String regex,int limit)--------拆分成指定的个数
8.其他方法:
public boolean isEmpty()-----------------------------判断是否是空字符串,不是null
public int length()----------------------------------取得字符串内容的长度
public String toLowerCase()--------------------------所有内容变为小写
public String toUpperCase()--------------------------所有内容变为大写
public String trim()--------------------------------去掉左右空格,中间的无法去掉

StringBuffer类

为什么使用StringBuffer类

字符串的不变性:

  1. 一个String对象的长度是固定的,不能改变它的内容,或者是附加新的字符到String对象中。
  2. 您也许会使用+来串联字符串以达到附加新字符或字符串的目的,但+会产生一个新的String对象。
  3. 如果程序对这种附加字符串的需求很频繁,系统会频繁在内存中创建String对象,造成性能下降。所以并不建议使用+来进行频繁的字符串串联。应该使用java.lang.StringBuffer类。

StringBuffer的使用

长度经常变化的字符串,可以考虑使用StringBuffer

//建议长度经常变化的字符串,采用StringBuffer

StringBuffer buffer = newStringBuffer();

buffer.append(“hello”);

buffer.append(“world”);

StringBuffer和StringBuilder

StringBuilder与StringBuffer的用法完全一致,唯一的区别是StringBuffer是线程安全的,而StringBuilder不是线程安全的。所以StringBuilder的性能要比StringBuffer要好。

单线程推荐使用StringBuilder,多线程使用StringBuffer。

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值