Java随笔2
作用1:搭配new关键字,创建类的对象作用2:在创建对象的同时,可以给对象的相关属性赋值
使用说明 >构造器声明的格式:权限修饰符类名(形参列表){} >创建类以后,在没有显示提供任何构造器的情况下,系统会默认提供一个空参的构造器,且构造器的权限与类声明的权限相同。 >一旦类中显示声明了构造器,则系统不再提供默认的空参的构造器。
构造器: public Student(String n,int a,String s,String m){ name=n; age=a; school=s; major=m; } public String getInfo(){ return "name= "+name+",age= "+age+",school= "+school+",major= "+major; }public class StudentTest {
public static void main(String[] args) {
Student s1=new Student("连君贤",22,"西安工程大学","计算机技术");
System.out.println(s1.getInfo());
Student s2=new Student("樊世豪",22,"淮阴工学院","计算机技术");
System.out.println(s2.getInfo());
}
}
②进阶
this
如形参名和属性名同名了,如何在方法内区分?使用this。 使用this修饰的变量,表示的是属性。没有用this修饰的,表示的是形参。public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
this的理解:当前对象或当前正在创建的对象
可以使用 “this(形参列表)”格式,调用当前类中指定的构造器
注: “this(形参列表)”必须声明在当前构造器的首行 “this(形参列表)”在构造器中最多声明一个
如果一个类中声明了n个构造器,则最多有n—1个构造器可以声明有“this(形参列表)”的结构
super
super的理解:父类的
注:同名的方法和属性 继承后创建对象:方法会覆盖,属性不会覆盖 即 id=0; person.id=1
子类继承父类以后可以在子类的方法或构造器中,调用父类中声明的属性或方法。
需要使用“super.”的结构,表示调用父类的属性或方法。一般情况下,可以考虑省略“super.”的结构。
但如果出现子类重写了父类的方法或子父类中出现了同名的属性时,则必须使用“super.”的声明,显式的调用父类被重写的方法或父类中声明的同名的属性。
调用父类构造器
①子类继承父类时,不会继承父类的构造器。只能通过“super(形参列表)”的方式调用父类指定的构造器。 ②规定:“super(形参列表)”,必须声明在构造器的首行。
public class Interview01 public static void main(String[] args){ new A(new B()); } //先执行new B 再A
就是子类的构造器一定会默认调父类的默认构造器
继承性
减少了代码冗余,提高了代码的复用性。更有利于功能的扩展。 让类与类之间产生了is—a的关系,为多态的使用提供了前提,这种关系是:is—a的关系。父类更通用、更一般,子类更具体。由于封装性的影响,可能子类不能直接调用父类中声明(private)的属性或方法。
Java中声明的类,如果没有显式的声明其父类时,则默认继承于java.lang.Object
Java只支持单继承,不支持多重继承
方法重写
子类需要对父类中继承过来的方法进行覆盖、覆写的操作。称为方法的重写。
①父类被重写的方法与子类重写的方法的方法名和形参列表必须相同。②子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
>子类不能重写父类中声明为private权限修饰的方法。
③关于返回值类型:
>父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型必须是void
>父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须 与被重写的方法的返回值类型相同。
>父类被重写的方法的返回值类型是引用数据类型(比如类),则子类重写的方法的返回 值类型可以与被重写的方法的返回值类型相同或是被重写的方法的返回值类型的子类
多态性
不同对象用同一个方法表现出来的不同行为
格式:Object obj=new String("hello");父类的引用指向子类的对象。
//多态性之前的场景: Person p1 =new Person(); Man m1=new Man(); //多态性: Person p2 =new Man(); 注:前提是Man是Person的子类
编译看类型(左) 运行看对象(右)
使用前提:①要有类的继承关系②要有方法的重写
适用于方法 不适用于属性
public static void main(String[] args){ AnimalTest test=new AnimalTest(); test.adopt(new Dog()); } public void adopt(Animal animal){ //Animal animal=new Dog() animal.eat(); animal.jump(); }
向上转型 Person p1= new Man();
向下转型 Man m1 =(Man)p1;
1.建议在向下转型之前,使用instanceof进行判断,避免出现类型转换异常 2.格式:a instanceOf A:判断对象a是否是类A的实例。 3. 如果a instanceOf A 返回true,则:a instanceOf superA 返回也是true。其中,A 是superA的子类。
Object类
类java.lang.Object是类层次结构的根类,即所有其它类的父类。每个类都使用Object作为超类。
equals
比较两个对象的引用地址是否相同。或比较两个对象是否指向了堆空间中的同一个对象实体
基本数据类型用==,引用数据类型已重写equals方法,比较内容
==:运算符区别
==: ①使用范围:基本数据类型、引用数据类型 ②基本数据类型:判断数据值是否相等 char c1 ='A'; int i3 = 65; sout(c1 == i3);//trueI float f1 12.0F;
int i4 = 12;
sout(f1 = i4);//true
引用数据类型变量:比较两个引用变量的地址值是否相等。
equals():方法 >使用范围:只能使用在引用数据类型上。 >具体使用:对于类来说,重写equals()和不重写equals()的区别。
③高级
static
static:静态的static 用来修饰的结构:属性、方法;代码块、内部类;
>静态变量:在内存空间中只有一份,被类的多个对象所共享。 >实例变量:类的每一个实例(或对象)都保存着一份实例变量。
可以通过“类.静态方法”的方式,直接调用静态方法 静态方法内可以调用静态的属性或静态的方法。(属性和方法的前缀使用的是当前类,可以省略) 不可以调用非静态的结构。(比如:属性、方法) > 类方法 实例方法 类 yes no 对象 yes yes >static修饰的方法内,不能使用this和super >补充:在类的非静态方法中,可以调用当前类中的静态结构(属性、方法)或非静态结构(属性、方法)
开发中,什么时候需要将属性声明为静态的? >判断当前类的多个实例是否能共享此成员变量,且此成员变量的值是相同的。 >开发中,常将一些常量声明是静态的。比如:Math类中的PI什么时候需要将方法声明为静态的?
>方法内操作的变量如都是静态变量的话,则此方法建议声明为静态方法
>开发中,常常将工具类中的方法,声明为静态方法。比如:Arrays类、Math类
单例模式
饿汉式: public class BankTest public static void main(String[] args){ Bank bank1=Bank.getInstance(); Bank bank2=Bank.getInstance(); System.out.println(bank1 == bank2); } 输出:trueclass Bank{
//1.类的构造器私有化
private Bank(){
}
//2.在类的内部创建当前类的实例
//4.此属性也必须声明为static的
private static Bank instance=new Bank();
//3.使用getXxx()方法获取当前类的实例,必须声明为static的
public static Bank getInstance(){
return instance;
}
懒汉式 //调用方法时才创建 省内存 class GirlFriend{ //1.类的构造器私有化 private GirlFriend(){ } //2. 声明当前类的实例 //4,此属性也必须声明为static的 private static GirlFriend instance null; //3. 通过getXxx()获取当前类的实例,如果未创建对象, public static GirlFriend getInstance(){ if(instance == null){ instance = new GirlFriend(); } return instance; }
二者对比:
特点: >饿汉式:“立即加载”,随着类的加载,当前的唯一实例就创建了 >懒汉式:“延迟加载”,在需要使用的时候,进行创建。 优缺点: >饿汉式:(优点)写法简单,由于内存中较早加载,使用更方便、更快。是线程安全的。(缺点)内存中占用时间较长。 >懒汉式:(缺点)线程不安全(放多线程章节时解决)(优点)在需要的时候进行创建,节省内存空间。
代码块
①静态代码块 //只能用static修饰
随着类的加载而执行 由于类的加载只会执行一次,进而静态代码块的执行,也只会执行一次 静态代码块内部只能调用静态的结构(即静态的属性、方法),不能调用非静 态的结构(即非静态的属性、方法) 作用就是初始化类的信息
②非静态代码块
随着对象的创建而执行 每创建当前类的一个实例,就会执行一次非静态代码块 非静态代码块内部可以调用静态的结构(即静态的属性、方法), 也可以调用非静态的结构(即非静态的属性、方法) 作用就是初始化对象的信息
两者内部均可声明变量 调用属性方法编写输出语句等 且静态代码块执行顺序优于非静态
赋值语句
1.可以给类的非静态的属性(即实例变量)赋值的位置有: 默认初始化 显式初始化 构造器中初始化 代码块中初始化 ********************** 有了对象以后,通过“对象.属性”或“对象.方法”的方法进行赋值
final
最终的 final可以用来修饰的结构:类、方法、变量 具体说明: final修饰类:表示此类不能被继承。 比如:String、StringBuffer、StringBuilder类 final修饰方法:表示此方法不能被重写 比如:Object类中的getClass() final修饰变量: 既可以修饰成员变量,也可以修饰局部变量。 此时的“变量”其实就变成了“常量”,意味着一旦赋值,就不可更改。 方法内声明的局部变量: 在调用局部变量前,一定需要赋值。而且一旦赋值,就不可更改方法的形参 在调用此方法时,给形参进行赋值。而且一旦赋值,就不可更改
final和static搭配:全局常量 eg:Math.PI
abstract
public abstract void eat(); //抽象方法 没有方法体
包含抽象方法的类一定是抽象类
因为方法是抽象方法 不能被调用,
要想不能被调用就不能创建对象,就需要把类也抽象化
如果继承了抽象方法,那么子类要么是抽象类,要么实现其父类的抽象方法
子类必须重写父类中的所有的抽象方法之后,方可实例化。否则,此子类仍然是一个抽象类。
不能用abstract修饰:私有方法、静态方法、final的方法和类。 私有方法不能重写 避免静态方法使用类进行调用 final的方法不能被重写 final修饰的类不能有子类
eg: abstract class Template{ public void spendTime(){ long start = System.currentTimeMillis(); code(); long end = System.currentTimeMillis(); long spend = end - start; System.out.println("花费时间:" + spend); }public abstract void code();
}
class TemplateTest{
public static void main(String[] args) {
PrintPrimeNumber p=new PrintPrimeNumber();
p.spendTime();
}
}
class PrintPrimeNumber extends Template{
@Override
public void code() {
//10000以内的质数
for (int i = 2; i <= 100000;i++){
boolean isFlag =true;
for (int j= 2; j<= Math.sqrt(i); j++){
if (i% j== 0) {
isFlag =false;
break;
} }
if (isFlag){
System.out. println(i);}} }}
interface
类是对象的封装 接口是功能的封装
>可以声明: 属性:必须使用public static final修饰 方法:jdk8之前:声明抽象方法,修饰为public abstract >不可以声明:构造器、代码块等
interface Flyable{//接口 //全局常量 public static final int MIN_SPEED =0; //可以省略public static final int MAX_SPEED 7900; //方法可以省略public abstract 声明 void fly(); }
接口和类的关系:实现关系
格式:class A extends SuperA implements B,C{} A相较于SuperA来讲,叫做子类;A相较于B,C来讲,叫做实现类。 >类可以实现多个接口。 >类针对于接口的多实现,一定程度上就弥补了类的单继承的局限性。 >类必须将实现的接口中的所有的抽象方法都重写(或实现),方可实例化。 否则,此实现类必须声明为抽象类。
接口与接口之间为继承关系 且为多继承
接口的多态性:接口名 变量名=new 实现类对象;
面试题:区分抽象类和接口 >共性:都可以声明抽象方法 都不能实例化 >不同:①抽象类一定有构造器。接口没有构造器 ②类与类之间继承关系, 类与接口之间是实现关系,接口与接口之间是多继承关系
1 接口中声明的静态方法只能被接口来调用,不能使用其实现类进行调用。2 接口中声明的默认方法可以被实现类继承,实现类在没有重写此方法的情况下,默认调用接口中声明的/默认方法。如果实现类重写了此方法,则调用的是自己重写的方法。
3 类实现了两个接口,而两个接口中定义了同名同参数的默认方法。则实现类在没有重写此两个接口//默以方法的情况下,会报错。—>接口冲突
要求:此时实现类必须要重写接口中定义的同名同参数的方法。4 子类(或实现类)继承了父类并实现了接口。父类和接口中声明了同名同参数的方法。(其中,接口中的方法//是默认方法)。默认情况下,子类(或实现类)在没有重写此方法的情况下,调用的是父类中的方法。———>类优先原则
内部类
具体来说,当一个事物A的内部,还有一个部分需要一个完整的结构B进行描述,而这个内部的完整的结构B又只为外部事物A提供服务,不在其他地方单独使用,那么整个内部的完整结构B最好使用内部类。总的来说,遵循高内聚、低耦合的面向对象开发原则。
分类 成员内部类:直接声明在外部类的里面。局部内部类:声明在方法内、构造器内、代码块内
如何创建?
//1.创建Person的静态的成员内部类的实例 Person.Dog dog=new Person.Dog(); dog.eat(); //2.创建Person的非静态的成员内部类的实例 Person.Bird bird = new Person Bird();//报错 Person p1=new Person(); Person.Bird bird = p1.new Bird();//正确的
枚举类
开发中,如果针对于某个类,其实例是确定个数的。则推荐将此类声明为枚举类。
枚举类内部定义的枚举值就是该类的实例,且必须在第一行定义 当类初始化时,这些枚举值会被实例化,互相以逗号分隔。
Enum
使用enum关键字定义的枚举类,默认其父类是java.lang.Enum类 使用enum关键字定义的枚举类,不要再显示的定义其父类。否则报错。
枚举类实现接口的操作 情况1:枚举类实现接口,在枚举类中重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是同一个方法。 情况2:让枚举类的每一个对象重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是不同的实现的方法。
单元测试
@Test public void tes2(){ System.out.println("hello11"); System.out.println("number="+number); } @Test标记的方法本身必须是public,非抽象的,非静态的,void无返回值,()无参数的。
包装类
为使得基本数据类型的变量具备引用数据类型变量的相关特征(比如:封装性、继承性、多态性),给各个基本数据类型的变量都提供了对应的包装类。
byte - Byte short - Short int - Integer long - Long float - Float double->Doublechar - Character
boolean -> Boolean
eg
/* 基本数据类型———>包装类:①使用包装类的构造器包装类———>基本数据类型: */ @Test public void test1(){ int i1 = 10; Integer ii1=new Integer(i1); System.out.println(ii1.toString()); }//推荐使用:
int i2 = 10;
Integer ii2 = Integer.valueOf(i2);
包装类———>基本数据类型 @Test public void test2(){ Integer ii1 = new Integer(10); int i1 = ii1.intValue(); i1 = i1 + 1; }
自动装箱 @Test public void test4(){ //自动装箱:基本数据类型———>包装类 int i1 = 10; Integer ii1=i1;//自箱 System.out. println(ii1.toString()); Integer ii2=i1+1;// //自箱 Boolean bb1 = true;// 自动拆箱: 包装类———>基本数据类型 int i2 = ii1;
基本数据类型、包装类---->String
基本数据类型、包装类———>String类型: 法一: valueOf @Test public void test1){ int i1 = 10; String str1=String.valueOf(i1); System.out.println(str1);//"10" } 法二: String str4 = i1 + "";
String类型—>基本数据类型、包装类
调用包装类的静态方法:parseXxx()/ @Test public void test2(){ String s1 = "123"; int i1 = Integer.parseInt(s1); }
5.异常处理
异常:指的是程序在执行过程中,出现的非正常情况,如果不处理最终会导致JVM的非正常停止。
|———java.lang.Exception:异常。可以编写针对性的代码进行处理。
|———编译时异常:(受检异常)在执行javac.exe命令时,出现的异常。
|———运行时异常:(非受检异常)在执行java.exe命令时,出现的异常。
|———java.lang.Error:错误。Java虚拟机无法解决的严重问题。
如:JVM系统内部错误、资源耗尽等严重情况。
一般不编写针对性的代码进行处理。
I---- StackOverflowError, OutOfMemoryError
常见的异常
运行时异常
--- ArrayIndexOutofBoundsException 输出角标越界
--- NullPointerException 空指针异常
--- ClassCastException 强转异常
--- NumberFormatException
---InputMismatchException 需要类型与输入类型不匹配
--- ArithmeticException 算术异常
编译时异常
----ClassNotFoundException
----FileNotFoundException
----IOException
try-catch-finally
try{
../可能产生异常的代码
}
catch(异常类型1 e){
.....//当产生异常类型1型异常时的处置措施
}
catch(异常类型2 e){
.....//当产生异常类型2型异常时的处置措施
}
finally{
.....//无论是否发生异常,都无条件执行的语句
}
注:将可能出现异常的代码声明在try语句中。一旦代码出现异常,就会自动生成一个对应异常类的对象。并将此对象抛出。针对于try中抛出的异常类的对象,使用之后的catch语句进行匹配。一旦匹配上,就进入catch语句块进行处理。一旦处理结束,代码就可继续向下执行。
如果声明了多个catch结构,不同的异常类型在不存在子父类关系的情况下,谁声明在上面,谁声明在下面都可以。如果多个异常类型满足子父类的关系,则必须将子类声明在父类结构的上面。否则报错。
try中声明的变量出了try结构后 就不可以进行调用了
catch中异常处理的方式:
①自己编写输出的语句。
② printStackTrace():打印异常的详细信息。(推荐)
③ getMessage():获取发生异常的原因。
finally
无论try中或catch中是否存在仍未被处理的异常,无论try中或catch中是否存在return语句等,finally中声明的语句都一定要被执行。
public static int test(String str) {
try {
Integer.parseInt(str);
return 1;
} catch (NumberFormatException e) {
return -1;
} finally {
System.out.println(“test结束”);
return 0;
}}
抛出异常 先不执行return-1,先到finally 然后被return0抢走
最后输入return的值为0
finally语句和catch语句是可选的,但finally不能单独使用
重点:将流资源的关闭操作声明在finally中
throws+异常信息
参照狼来了案例
public void test() throws 异常类型1,异常类型2,..{
//可能存在编译时异常
}
从编译是否能通过的角度看,看成是给出了 异常万一要是出现时候的解决方案。此方案就是,继续向上抛出(throws)。但是,此throws的方式,仅是将可能出现的异常抛给了此方法的调用者。此调用者仍然需要考虑如何处理相关异常。从这个角度来看,throws的方式不算是真正意义上处理了异常。