【Java基础系列】第六章 面向对象(下)

6.1 包装类

6.1.1 基本类型对应的包装类

基本数据类型

对应的包装类

byte

Byte

short

Short

int

Integer

float

Float

double

Double

char

Character

boolea

Boolean

6.1.2 自动装箱与自动拆箱

(1)定义:自动装箱:可以把一个基本类型遍历直接赋值给对应的包装类变量或object类

    自动拆箱:允许直接把包装类对象直接赋给一个对应的基本类型变量

  1. 例子:

Integer  inObj  =  5;      //直接把一个基本类型变量赋值给Integer对象(自动装箱)

Object  boolObj  =  true; //直接把一个boolean类型变量赋值给Object变量(自动装箱)

int  it  =  inObj;         //直接把一个Integer对象赋值给int类型变量(自动拆箱)

6.2.3 字符串与基本类型之间的转换

①String类型 转为 基本类型

String  strInt  =  “123”;

String  strFlo  =  “4.31”;

//把一个特定字符串转换成int变量

int  a  =  Integer.parseInt( strInt );

int  b  =  new Integer( strInt );

②String类型 转为 包装类型

//String 类型转为 Integer 包装类

Integer  i  =  Integer.valueOf( “6543” ) ;

③基本类型 转为String类型

//把一个特定的字符串转换为float变量

Float  float1  =  Float.parseFloat( strFlo );

Float  float2  =  new Float(strFlo );

//float变量转换为String变量

String  floStr  =  String.valueOf( 2.414f );

//double变量转换为String变量

double  douStr  =  String.valueOf( 6.232 );

//boolean变量转换为String变量

boolean  booStr  =  String.valueOf( true );

Ps:  Integer  integer1  =  150;

Integer  integer2  =  150;

integer1  ==  integer2 ----->  false -----> 因为 缓存数组:-128~127之间的整型数

6.2 == 和 equals

Integer i1 = 2;                  创建了一个整型对象

Integer i2 = Integer.valueOf(2);    不创建新的对象,i2和i1引用同一个对象

Integer i3 = Integer.valueOf(2);    不创建新的对象,i3和i1引用同一个对象

Integer i4 = Integer.valueOf("2");   创建了一个整型对象

Integer i5 = Integer.valueOf("2");   创建了一个整型对象

根据对象的创建过程,很明了,程序运行结果为:

test ==

i1 == i2 ? true

i1 == i4 ? false

i2 == i3 ? true

i2 == i4 ? false

i4 == i5 ? false

test equals

i1.equals(i2) ? true

i1.equals(i4) ? true

i2.equals(i3) ? true

i2.equals(i4) ? true

i4.equals(i5) ? true

6.2.1 基本数据类型

①==    比较内容

②equals   比较内容

6.2.2 引用类型

①== 比较地址

Ps:必须要同一类型 或者两者必须存在继承关系,否则编译不通过

②equals 比较内容

例://实现自己的equals,比较引用类型的内容

 public class EqualTest{

public static void main( String[] args ){

String s1 = "A";

String s2 = new String( "A" );

//equals 不是 String 自己的方法, 它也是 Object 类里面定义方法

//只是 String 对它进行了复写

System.out.println( s1.equals( "A" ) );   //true

System.out.println( s1.equals( s2 ) );    //true

Person p1 = new Person( "Limin", 25 );

//Person p2 = p1;

//Person p2 = new Person( "Limin", 25 );

System.out.println( "[015]"+ p2.equals( p1 ) );

}

}

//为了给我自己定义的类, 做一个等值判断的标准方法

class Person{

String name;

int age;

public Person( String _name, int _age ){

name = _name;

age = _age;

}

//只要名字一样, 年龄一样, 我就认为他是同一个人

//public boolean equals( Object o )

public boolean equals( Object o ){

if( o==this )

return true;    //因为两个对象引用地址一样

if( o!=null ){

//instanceof:

if( o.getClass()==Person.class ){

Person p = (Person)o;

if( this.name!=null && p.name!=null

&& this.name.equals(p.name)

&& this.age == p.age ){

return true;

}

}

}

return false;

}

}

6.3 常量池

6.4 final修饰符

6.4.1 final修饰成员变量

  1. 程序员必须给成员变量做显式初始化,初始化后不可改变值

(2)初始化位置:

[1]非静态成员变量:

①声明时初始化

②初始化块中初始化

③构造器中初始化

[2]静态成员变量(类变量):

①声明时初始化

②静态初始化块中初始化

6.4.2 final修饰局部变量

  1. 声明时可以初始化或不初始化,要使用时必须初始化,初始化后不可改变值
  2. 初始化位置:

[1]方法体、语句块中的局部变量

①声明时初始化

②方法块中初始化

[2]形参列表中的局部变量

没初始化这一说,使用时也可以不初始化

6.4.3 final修饰基础类型和引用类型区别

(1)final修饰的基础类型表示值不可修改

(2)final修饰的引用类型表示引用的地址不可修改,但该引用中的非final修饰的属性和方法等是可以修改的

6.4.4 可执行宏替换的final变量

(1)定义:宏变量也称直接量(常量),已改全改。

(2)要求:①使用final修饰

②定义时初始化

③该初始值可以编译时就被确定下来

6.4.5 final修饰方法

(1)final修饰的方法不可被子类重写,但可以被继承

(2)子类重写父类非final的方法时,可以定义为final修饰的方法

6.4.6 final修饰类

  1. final修饰的类不可被继承,final类中的方法默认是final的
  2. 可以通过使用final修饰类的对象 配合 获取该类属性方法返回值中new该类对象,来实现该final修饰的类的属性或方法不被修改的效果,从而达到保护类中属性安全目的。

6.5 抽象类

6.5.1 抽象类的意义与特性

  1. 意义:

父类无法确认该方法具体的行为,从而让子类重写该抽象方法,添加其各自不同的具体行为,子类重写的方法不能再添加abstract。

  1. 特性:

①抽象类内可以没有抽象方法,但类内有抽象方法时,该类必须定义为抽象类

②如果没有实现完父类的抽象方法,那该类也必须定义为抽象类

③把多态用的灵活,通过模板来让子类实现

④abstract不能用来修饰任何的变量

⑤不可用private修饰任何抽象方法 (因为priavte会方法不可见,无法重写)

⑥不可用static修饰任何抽象方法

⑦static 与 abstract完全互斥吗 ------->可以应用到内部类中

6.5.2 抽象类定义格式

(修饰符)  abstract  class  名字{   }

Ps:只要类中有一个抽象方法,此类就被标记为抽象类

6.5.3 抽象类属性和方法定义格式

(1)常量、变量、方法、语句块的定义格式和普通类一样

(2)抽象方法的定义格式:

格式1: (修饰符)  abstract  数据类型  名字();

格式2: (修饰符)  abstract  数据类型  名字(参数列表);

6.5.4 抽象类内包含数据

 

抽象类里可以有:常量、变量、普通方法、抽象方法、语句块、对象

 

6.5.5 抽象类的调用与被调用

  (1)抽象类调用普通类和接口:

①抽象类调用普通类和接口都跟普通类调用的一样。但是调用接口时,不一定要重写其 中的抽象方法。

  (2)抽象类被调用:

抽象类的调用只能通过继承extends来调用,从而获得抽象类里的特性,普通类名的 后面继承抽象类,抽象类除了被继承外没有任何意义,抽象类中抽象方法必须要被子类 重写。

如:public  class  普通类名  extends  抽象类名{ }

抽象类无法被接口调用,因为接口只能通过new来调用类,而抽象类只能通过继承 被调用,不能通过new被调用。

6.6 接口

6.6.1 定义格式

     访问权限 interface 名字 { }

     类实现接口 :类名 implements 要实现的接口名

       (其中,类可以实现多个接口,中间用,号隔开

6.6.2 接口的特性

[1]接口中的方法默认都是public,abstract修饰,属性默认都是static、final修饰

[2]接口中可以有 内部类、枚举、接口

[3]接口中不可以定义static方法和default方法,这两种方法都有方法体(JDK1.8以下)

[4]接口不可以实例化(即不可以new)

[5]定义接口可以用:default,public

6.6.3 接口中的数据

     ①  常量

     ②  抽象方法 (JDK1.8以上可以定义static方法和default方法 [有方法体])

     ③  对象(内部类、枚举、接口等)

     其中,修饰常量的修饰符可有省略。

6.6.4 抽象方法的定义格式

     格式1  访问权限 abstract 数据类型 方法名();

     格式2  访问权限 abstract 数据类型 方法名(参数);

     其中,abstract可有省略。

6.6.5 匿名接口(也是匿名类)

     (1)定义格式:

已有接口名 命名=new 已有接口名(){  匿名接口  };

     (2)匿名接口数据:

①  常量

      ②  抽象方法

       ③  普通方法

④  初始化块(不允许静态初始化块)

⑤  对象

6.6.6 工厂模式

6.6.7 命令行模式

6.7 内部类

6.7.1 内部类的定义

在一个类的内部,定义一个类,这个类称为“内部类/嵌套类”

6.7.2 内部类作用

  1. 可以访问外部类中的成员,包括private成员
  2. 外部类可以创建内部类对象,通过该对象引用可以获取内部类中的成员

6.7.3 内部类的特性:

  1. 定义位置与个数:

内部类的定义位置只要在类内即可;内部类个数没有限制

  1. 内部类编译:

内部类编译后,也会生成  .class 文件。

格式:[外部类名]$[内部类名].class

 例:Outer$Inner.class

  1. 内部类的调用:

在一个类中,要使用另一个类的内部类,先要创建这个外部类的实例,再通过外部类的实例来创建内部类的实例,从而起到调用内部类的作用。

  1. 内部类的继承与实现:内部类可继承其他类或实现接口。

1)静态内部类可以有静态成员,而非静态内部类则不能有静态成员2)静态内部类的非静态成员可以访问外部类的静态变量,而不可访问外部类的非静态变量3)非静态内部类的非静态成员可以访问外部类的非静态变量。

6.7.4 内部类可用的修饰符

  1. 权限修饰符:private 、(默认)、protected、public
  2. abstract 、final 都可以应用到内部类
  3. abstract 、static可以共用

6.7.5 内部类中可以拥有的成员

(1)非静态的内部类:不可以定义静态的成员

成员变量、行为方法、构造器、语句块(普通)、内部类

(2)静态内部类:可以定义静态的成员

6.7.6 访问外部类与内部类同名属性或方法

调用格式:外部类名.this.属性或者方法

例:调用外部类同名属性: Outer.this.score;

6.7.7 private修饰的内部类数据的调用

//private修饰的内部类的数据调用

public class InnerTest

{

public static void main( String[] args ){

Outer out = new Outer();

//错误: Outer.Inner可以在Outer中访问private

//Outer.Inner in = out.new Inner();

//限定不可以访问这一种类型: Outer.Inner

//Outer.Inner in = out.getInner();

A in = out.getInner( ); //将外部类实例.获取到的内部类引用赋给他实现的接口

String s = in.getName(); //通过内部类的实例获取到其private修饰的name属性

System.out.println( ""+ s );

}

}

//外部类

class Outer{

private String oName = "OName";

public void OutTest(){

}

//内部类,设置为 private

private class Inner implements A{

private String name = "";

public Inner( String name ){

this.name = name;

}

//实现接口中的getName()方法,返回name

public String getName(){

return name;

}

}

public Inner getInner(){

return new Inner( oName );

}

}

//A接口

interface A{

public String getName();

}

6.7.8 局部内部类(在方法体内的内部类)

  1. 实例化位置:

局部内部类只能在当前方法体中,创建该局部内部类之后实例化。

  1. 快捷定义方式:

[1]创建:

通过new一个类( ){ }; 创建一个对象,实际上它是创建一个匿名的内部类。

[2]调用:

①直接在后面加 .方法( )  或  .属性

②用变量来保存该内部类的引用,通过引用来调用方法或属性。

( ps:该引用的所属类必须要存在要调用的成员。)

例1:

//匿名内部类

public class InnerTest

{

public static void main( String[] args ){

Outer out = new Outer();

out.OutTest();

}

}

//外部类

class Outer {

//方法OutTest()

public void OutTest(){

//通过 .方法() 来调用匿名内部类内的方法

new Object(){

private String name = "Hello";

public void getName(){

System.out.println( "[A] --> name: "+ name );

}

}.getName();

//用Object类型变量来保存匿名内部类的引用

Object o = new Object(){

private String name = "Hello";

public void getName(){

System.out.println( "[A] --> name: "+ name );

}

};

//错误: 找不到符号

o.getName();  //使用的是 Object 对象, 因为 Object 没有这个方法

}

}

例2:

//从内部类中访问局部变量i; 需要被声明为最终类型 final

public class InnerTest

{

public static void main( String[] args ){

Outer out = new Outer();

out.OutTest();

//out.test2();

}

}

//外部类

class Outer {

public A a;

//OutTest()方法

public void OutTest(){

int i = 5;

a = new A(){

public void test(){

//错误: 从内部类中访问局部变量i; 需要被声明为最终类型 final

System.out.println( "i: "+ i );

}

};

}

//test2()方法

public void test2(){

a.test();

}

}

//A类型,用于创建局部匿名内部类

class A {

public void test(){ }

 

6.7.9 类与接口的嵌套

一个对象嵌套在另一个对象里面,这个对象就叫嵌套型事物。对象内可以嵌套类(包括 普通类以及抽象类)或者接口

(1)class←嵌套→class

class

类的定义与调用

数据的调用

静态内部类

定义:static class 静态内部类类名{     };

调用:①外部类名.静态内部类类名 命名=new 外部类名.静态内部

      类类名();

     ②继承外部类,然后

       静态内部类类名 命名=new 静态内部类类名();

命名.被调用数据;

非静态内部类

定义:class 非静态内部类类名{     };

调用:外部类名.非静态内部类类名 命名=new 外部类名().new 非静态内部类类名();

命名.被调用数据;

(静态或非静态)

匿名内部类

定义:已有类类名 变量名=new 已有类类名(){     };

调用:①外部类名 命名=new 外部类名();   (直接实例化外部类)

      ②已有类类名 命名=new 外部类名().变量名;

无法调用数据

局部内部类

(不能是静态)

定义:同 非静态内部类 (需要定义在方法体里)

调用:只能在方法体内调用:

      局部内部类类名 命名=new 局部内部类类名();

命名.被调用数据

(只能在方法体内,定义的位置之后调用)

局部匿名内部类(不能是静态)

定义:同 匿名内部类 (需要定义在方法体里)

调用:外部类名 命名=new 外部类名();

      命名.所在方法名(); 或在定义后面加.调用数据  

  (直接调用所在方法即可)

无法调用数据

      

(2)class←嵌套→interface

interface

接口的定义与调用

数据调用

有名内部接口

(常量,抽象方法,对象)

定义:interface 接口名{      };

调用:①接口名.被调用数据

      ②实现接口implements 接口名 后直接写 被调用数据

① ②

匿名内部接口

(常量,变量,普通方法,普通语句块,对象)

定义:已有接口名 命名=new 已有接口名(){     };

调用:外部类名 命名=new 外部类名();   (跟匿名类一样)

无法调用数据

(3)interface←嵌套→class

class

类的定义与调用

数据调用

(静态或非静态)

内部类

定义:(static) class 静态或非静态内部类类名{     };

调用:①实现或不实现接口都可以

        内部类类名 命名=new (接口名.)内部类类名();

命名.被调用数据

(静态或非静态

匿名内部类

定义:已有类类名 变量名=new 已有类类名(){     };

调用:无法调用

无法调用数据

(4)interface←嵌套→interface

interface

接口的定义与调用

数据调用

有名内部接口

(常量,抽象方法,对象)

定义:interface 接口名{      };

调用:①内部接口名.被调用数据

     ②实现接口implements 内部接口名 后直接写 被调用数据

① ②

匿名内部接口

(常量,变量,普通方法,普通语句块,对象)

定义:已有接口名 命名=new 已有接口名(){     };

调用:外部接口名.命名

      ②实现外部接口后,直接写 命名

无法调用数据

6.8 枚举类

6.8.1 枚举类入门

(1)枚举类历史:

java5 新增了enum关键词(它与class、interface关键词的地位相同)。用以定义枚举类。

(2)枚举类成员:

枚举类可以有自己的成员变量、方法、可以实现一个或者多个接口;也可以定义构造器(构造器必须定义为private,默认也是private)

  1. 与普通类的相同点:

一个java源文件中最多只能定义一个public访问权限的枚举类,且该java源文件也必须和该枚举类的类名相同。

(4)枚举类与普通类的区别:

[1]枚举类默认继承了java.lang.Enum类,而不是默认继承Object类。因此枚举类不能显示的继承其他父类。

[2]枚举类默认使用final修饰,因此枚举类不能派生子类,所以枚举值必须为抽象方法提供实现

[3]枚举类的所有实例必须在其第一行显示列出,否则这个枚举类永远不能产生实例。列出来的这些实例系统都自动添加public static final 修饰,无须程序员显示添加

  1. 作用:

使用枚举类可以使程序更加健壮,避免创建对象的随意性

6.8.2 例子

//测试类-----------------------------------------------------------------------

public class A13_EnumTest{

public static void main(String[] args){

//季节枚举实例

//SeasonEnum se = new SeasonEnum(); //枚举类型不能new

//[1]枚举类默认有一个values()方法,返回该枚举类的所有实例

for( SeasonEnum s : SeasonEnum.values()){

System.out.println( s );  //输出该枚举类的所有实例

}

//[2]使用枚举实例,通过EunmClass.varialbe形式来访问

SeasonEnum.SUMMER.judge(SeasonEnum.SUMMER);

//[3]枚举类中的ordinal()方法,用于获取枚举值在枚举类中的索引值(即声明的位置)

System.out.println("AUTUMN实例在SeasonEnum中的位置:" + SeasonEnum.AUTUMN.ordinal());

//[4]通过Enum的valueOf()方法获取指定枚举类的枚举值,从而获取该枚举值的属性或方法

Gender g1 = Enum.valueOf( Gender.class, "NO" );

Gender g2 = Enum.valueOf( Gender.class, "NOMAN" );

g1.name = "无";

g1.info();

g2.info();

}

}

//季节枚举类------------------------------------------------------------------

enum SeasonEnum{

SPRING, SUMMER, AUTUMN, WINTER;

public void judge( SeasonEnum s ){

switch( s ){

case SPRING:

System.out.println( "春天" );

break;

case SUMMER:

System.out.println( "夏天" );

break;

case AUTUMN:

System.out.println( "秋天" );

break;

case WINTER:

System.out.println( "冬天" );

break;

}

}

}

//性别枚举类-------------------------------------------------------------------

//[5]当开始使用枚举类的一个实例时,全部实例会自动实例化,由左到右

enum Gender implements GenderDesc{

NOMAN("不男"),

NO,

MAN("男"){      //为该实例添加自己的类体部分

public void info(){

System.out.println( "男士" );

}

},

WOMEN("女"){    //为该实例添加自己的类体部分

public void info(){

System.out.println( "女士" );

}

};

String name;  //枚举属性name

//无参构造器(默认修饰符private)

Gender( ){

System.out.println("[无参构造器]:" + this );

}

//有参构造器

private Gender(String name){

this.name = name;

System.out.println("[有参构造器]:" + this.name);  

}

//重写接口方法

public void info(){

System.out.println("[info()方法]:" + this.name);

}

}

//接口GenderDesc------------------------------------------------------------

interface GenderDesc{

void info();

}

6.9 类与接口之间的相互调用

                                     

调用方式

适用事物情况

implements  实现

类调用接口

extents   继承

类调用类,接口调用接口(可以连续继承多个)

直接用

类调用类、接口调用接口、类调用接口、接口调用类、其他和上面2种一样

import   导入

用在不同包之间的事物,可以同时用上面3种方式。

6.9.1 class←→class

      (1)直接用:

            调用类:new 类名();                  //调用并运行类

                    类名 变量名=new 类名();      //让变量的值=调用的类

            调用类的特性,如:

              //调用变量

                用法1:变量类型 变量名=new 类名().要调用的变量;

                用法2:类名 变量名1=new 类名();

                        变量类型 变量名2=变量名1.要调用的变量;

              //调用方法

                用法3: new 类名().要调用的方法名();

                用法4: 类名 变量名=new 类名();

                        变量名.要调用的方法名();

              //调用类的静态属性和方法:

类名.静态属性或方法

      (2)extends 继承:

                 类名 extends  要继承的类名

                 类之间继承后,可以在子类里直接使用父类的所有数据和方法

                 (注意:在static静态方法里要new 后才能使用)

      (3)继承类后,改写类里的方法:

         

 

6.9.2 class→interface

      (1)直接用:

          类调用接口:不需要调用就可以直接使用,如:

                 用法1:在代码里直接写上接口名;

                 用法2:(访问权限) 接口名 命名;

             ①在静态方法里调用的时候要添加static

             ②要重写接口的抽象方法

          类调用接口的特性:

                 用法1:(修饰符) 常量类型 命名=接口名.常量名;

                 用法2:接口名.常量名;   

  (2)implements 实现:

             格式:类名 implements 要实现的接口名

                 (其中,类可以实现多个接口,中间用,号隔开

      (3)调用后,改写接口里的方法

 

6.9.3 interface→class

      (1)直接用:

          接口调用类:访问权限 类名 命名=new 类名();

          接口调用类的特性:

                 用法1:(访问权限) 常量类型 命名=new 类名().常量

                 用法2:类名 命名=new 类名();

                        常量类型 常量名=命名.常量();

       (注意:变量和常量的调用方式相同,接口只能直接调用类的常量和变量

6.9.4 interface←→interface

      (1)直接用:

            常量类型 常量名=接口名.常量名;

           (注意:接口不能直接调用接口的抽象方法

      (2)extends 继承:

         接口名  extents  要继承的接口名,要继承的接口名,...... //可继承多个接口

         常量类型 常量名=常量名;//继承后直接使用父接口的数据,但不能调用抽象方法

6.10 Java垃圾回收

6.10.1 垃圾回收的对象

回收的对象:在堆上分配对象(空间)

6.10.2 强制垃圾清理

手动去调 System.gc( ) | Runtime.getRuntime( ).gc( )

通知垃圾回收器帮我们清理内存, 但是它不一定会完全的回收所有对象

6.10.3 垃圾自动回收流程

(1)"可达状态":创建一个对象时

(2)"可恢复状态":一旦没有被引用, 这个对象立即进行该状态

(3)”不可达状态”:当 JVM 内存紧张, 要回收一些内存, 某些 "可恢复状态"对象被调用finalize(),如果在 finalize() 没有任何恢复操作, 该对象进入 --> 不可达状态 [等待]--> 清理

(4)在被调用的finalize() 中可以对该对象恢复引用, 将置为  --> "可达状态",这样就不会被回收了

例子:

public class FinalizeTest{

int id;

private FinalizeTest ft1;

FinalizeTest( int _id ){

id = _id;

}

public static void main( String[] args ){

//没有要求 gc 去做清理的工作

for( int i=0; i<5; i++ ){

ft1 = new FinalizeTest( i );

//System.gc();    //强制 gc 回收无用的内存

Runtime.getRuntime().gc();  //强制 gc 回收无用的内存

}

ft1 = null;   //把这个对象置为 --> 可恢复的状态

System.out.println( "程序已结束!" );

}

//是 Object 类的方法

public void finalize(){

//可以在这一个方法, 恢复对象的引用

ft1 = this;   //这一个 this 就是将被回收的对象

System.out.println( "finalize: "+ id );

}

}

6.10.4 垃圾回收流程图

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

__Yvan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值