黑马程序员_java基础--面向对象(3)

本文详细介绍了面向对象编程中的多态概念,包括其实现机制、前提条件及优缺点,并探讨了对象类的基本方法与用途。此外,还深入解析了异常处理机制,包括异常体系结构、异常分类与处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

多态:

(1)同一个对象,在程序不同时刻的多种运行状态。举例:动物,狗是狗,狗是动物。水(气态,液态,固态)

     编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给变量的对象决定。如果编译时类型和运行时类型不同,就出现多态。

实现多态的机制:

      父类的引用变量可以指向子类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的真正实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
(2)多态前提
          A:存在着继承或者实现关系
          B:有方法的重写
          C:父类(接口)引用指向子类(实现)对象

(3)多态的好处和弊端:
     好处:多态的存在提高了程序的扩展性和后期可维护性
     弊端:虽然可以预先使用,但是只能访问父类中已有的功能,运行的是后期子类的功能内容。
       不能预先使用子类中定义的特有功能。
(4)多态中对象调用成员的特点
     Fu f = new Zi();
       A:成员变量
              编译看左边,运行看左边

       B:成员方法 

        在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
        在运行时期:参阅对象所属的类中是否有调用的方法。
        总结就是:

              编译看左边,运行看右边
       C:静态方法
               编译看左边,运行看左边

(5)多态的思想
       指挥同一批对象做事情。举例:带兵打仗,下课等。

package it.heima.com.duixiang;

public class DuoTaiDemo2 {
	public static void main(String[] args){
	/*	
		Fu1 fu = new Zi1();
		fu.A();
		System.out.println(fu.num);
		
		Zi1 z = new Zi1();
		z.A();
		System.out.println(z.num);
		*/
		//Fu1 f = new Zi1();
		//
//				System.out.println(f.num);
		//
//				Zi z = new Zi();
//				System.out.println(z.num);

				//f.method1();
				//f.method2();
				//f.method3();

				Fu1 f = new Zi1();
				System.out.println(f.num);
				f.method4();
				f.method2();

				Zi1 z = new Zi1();
				z.method4();
				z.method2();

	}
}

class Fu1{
	//int num = 1;
	 void A(){
		System.out.println("fu1 A-----");
	}
	 
	 static int num = 5;
		void method1()
		{
			System.out.println("fu method_1");
		}
		void method2()
		{
			System.out.println("fu method_2");
		}
		void method3()
		{
			System.out.println("fu method_3");
		}
		static void method4()
		{
			System.out.println("fu method_4");
		}

}

class Zi1 extends Fu1{
	//int num = 2;
	 void A(){
			System.out.println("zi1 A-----");
		}
	 
	 static int num = 8;
		void method1()
		{
			System.out.println("zi method_1");
		}
		void method3()
		{
			System.out.println("zi method_3");
		}

		static void method4()
		{
			System.out.println("zi method_4");
		}

}


object类:

(1)是所有类的根类,超类。
      java中提供的类以及我们自定义的类都直接或者间接的继承自Object类。
(2)Object类中的方法
       A:void finalize() 
               当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
       B:ClassgetClass()
               获取对象的字节码文件的描述类,后面再讲反射的时候还会在说这个类。
               String name = s.getClass().getName();
       C:int hashCode()
                获取对象的哈希值。其实就是对象的内存地址值十进制表示
       D:StringtoString()
               返回对象的字符串表示。
 表示格式:
 getClass().getName()+"@"+Integer.toHexString(hashCode());
例:

package it.heima.com.duixiang;

public class ObjectDemo {
	public static void main(String[] args){
	Demo3 d1 = new Demo3(4);
	//输出语句打印对象时,会自动调用对象的toString方法。打印对象的字符串表现形式。
	System.out.println(d1);
	
	Demo3 d2 = new Demo3(7);
	System.out.println(d2.toString());
	
	Demo3 d3 = new Demo3(5);
	Class c = d1.getClass();
	System.out.println(c.getName()+"@@"+Integer.toHexString(d1.hashCode()));
	System.out.println(d1.toString());
	
	Person p = new Person();
	System.out.println(d1.equals(p));
	}
}

class Person{
	
}

class Demo3 extends Object{
	private int num;
	Demo3(int num){
		this.num = num;
	}
	
	public boolean equals(Object obj){
		if(!(obj instanceof Demo3))
			return false;
		Demo3 d = (Demo3) obj;
		return this.num == d.num;
	}
	
	public String toString(){
		return "demo3:"+num;
		
	}
}



       一般我们输出对象名的时候,其实底层调用的就是该对象的toString()方法。
       这种返回没有意义,所以,我们会重写这个方法,显示类的成员变量信息。
       E:booleanequals(Object obj)
       用于比较两个对象的地址值是否相同
       我们获取对象后,比较它的地址值意义不大。所以也会对这个方法进行重写。
       重写要完成什么功能,是根据需求定的。
(3)==和equals的用法:
     A:==怎么用?
       **可以用于比较基本数据类型,比较的就是基本数据类型的值是否相等。
       **可以用于比较引用数据类型,比较的是对象的地址值是否相等。

      B:equals怎么用?
     equals只能用于比较引用数据类型的。
     **Object提供的equals是用于比较对象地址值是否相同。
      **自定义类中,如果重写了equals方法,那么就是按照你自己的需求来比较的。


内部类(次重点)
      (1)把一个类定义在某个类中的,这个类就被称为内部类,内置类,嵌套类。
      (2)访问特点:
             A:内部类可以直接访问外部类中的成员,因为内部类持有外部类的引用,
              格式为:外部类名.this
            B:外部类要想访问内部类的成员,必须创建对象访问。
      (3)内部类的访问格式:
           A:当内部类定义在外部类的成员位置,而且非私有,则可以在其他外部类中直接建立内部类对象
                格式:外部类名.内部类名  变量名 = new 外部类对象.内部类对象
                如:Outer.Inner in = new Outer().new Inner()
           B:当内部类在外部类成员位置,且被static修饰时
               **外部其他类可直接访问静态内部类的非静态成员
                格式:new 外部类名.内部类名().内部类成员
                如:new Outer.Inner().function();
                **外部其他类可直接访问静态内部类的静态成员
                格式:new 外部类名.内部类名.内部类成员
                如:new Outer.Inner.function();

private:将内部类在外部类中进行封装

static: 内部类具备static特性,

             当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。

注意:当内部类中定义了静态成员,该内部类必须是static的

           当外部类中的静态方法访问内部类时,内部类也必须是static的。

          (4)什么使用时候内部类呢?
               假如有A类和B类,A类想直接访问B类的成员,B类访问A类成员的时候,
               需要创建A类对象进行访问,这个时候,就可以把A类定义为B类的内部类。
          (5)内部类的位置
              A:成员位置
                  **可以被private修饰(Body,Heart)
                  **可以被static修饰。(它访问的外部类的成员必须是静态的)
             B:局部位置
                **可以直接访问外部类中的成员,因为还持有外部类的持用
               也可以直接访问局部成员,但是局部成员要用final修饰 
               注意:局部内部类不能用private和static修饰

class Outer{
	int x =3;
	void method(){
		final int y =4;
		class Inner{
			void function(){
				System.out.println(y); 
				//在内部类中访问局部变量y,需要被声明为最终类型。
			}
		}
		new Innner().function(); 
		//运行method()时,不会运行Inner类,非静态没对象,不运行,要新建一个对象。
	}
}


          (6)通过class文件我们就可以区分是否带有内部类,以及内部类的位置
               Outer$Inner:成员内部类
               Outer$1Inner:局部内部类


匿名内部类(局部内部类的简写) (重点)

适合只使用一次的类

不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建匿名内部类的对象。

匿名内部类不能定义构造器,因为匿名内部类没有类名。


                (1)前提:继承一个类或者实现一个接口
                     (注意不要弄混匿名内部类的前提和多态的前提)
               (2)格式:
                    new 父类名或者接口名()
                     {
                        重写父类方法或者实现接口中的方法。
                          也可以自定义其他方法。
                     };

其实,匿名内部类就是一个匿名子类对象,而且这个对象有点胖,可以理解为带内容的对象。
                (3)什么时候定义匿名内部类?
                 匿名内部类只是为了简化书写,匿名内部类有局限,通常定义匿名内部类时,该类方法不超过3个
                (4)匿名内部类的好处和弊端:
                 好处:简化代码书写
                   弊端:
                          不能直接调用自己的特有方法
                          不能执行强转换动作
                           如果该类里面方法较多,不允许使用匿名内部类


模板设计模式:
         在定义功能时,功能的一部分是确定的,有一部分是不确定的,而且确定的部分在使用不确定的部分,
         可将不确定的部分暴露出去,由该类的子类去完成。
         如:求一段程序的运行时间例子。


异常:
         (1)
异常:就是不正常,是指程序在运行时出现的不正常情况。其实就是程序中出现的问题。

                       这个问题按照面向对象思想进行描述,并封装成了对象。因为问题的产生有产生的原因、

                        有问题的名称、有问题的描述等多个属性信息存在。当出现多属性信息最方便的方式就是

                        将这些信息进行封装。异常就是java按照面向对象的思想将问题进行对象封装。这样就

                         方便于操作问题以及处理问题。

                         出现的问题有很多种,比如角标越界,空指针等都是。就对这些问题进行分类。而且这些

                          问题都有共性内容比如:每一个问题都有名称,同时还有问题描述的信息,问题出现的

                          位置,所以可以不断的向上抽取。形成了异常体系。

         (2)导致程序运行不正常的现象有很多,所以,就有很多的异常对象。
             而这些异常对象存在着共性的内容,所以,可以不断的进行抽取。最终形成了异常的体系结构。
              异常体系的根类是:Throwable
             Throwable:
              |--Error:通常是JVM出现的重大问题,我们处理不了。也不需要编写代码处理。比如说内存溢出。
              |--Exception:一般性的错误,是需要我们编写代码进行处理的。可以通过try、catch处理。
              |--RuntimeException:运行时异常,这个我们也不需要处理。
                   其实就是为了让他在运行时出问题,然后我们回来修改代码。
         (3)异常的分类
             异常有两种:
              编译时被检测异常:
             该异常在编译时,如果没有处理(没有抛也没有try),编译失败。
             该异常被标识,代表这可以被处理。
              运行时异常(编译时不检测)
             在编译时,不需要处理,编译器不检查。
             该异常的发生,建议不处理,让程序停止。需要对代码进行修正。
        (4)异常体系的特点:
               异常体系中的所有类及其子类对象都具备可抛性。也就是说可以被throw和throws关键字所操作。
        (5)main方法是如何处理异常的。
              A:在main里面编写代码进行处理
              B:交给jvm自己进行处理。采用的是jvm的默认处理方式。
                 其实就是相当于调用了异常对象的printStackTrace()方法。
         (6)Throwable类的学习
               getMessage():获取异常信息,返回字符串。
               toString():获取异常类名和异常信息,返回字符串。
                printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
        (7)异常的处理·
           A:try...catch...finally
           基本格式:

try{
	可能出现异常的代码
}
catch(异常对象){	
	异常处理代码
}
finally{
	释放资源
}

记住:catch适用于处理异常,如果没有catch就代表异常没有被处理过,如果该异常是检测时异常,那么必须声明。

变形格式:
try...catch
try...catch...catch...
try...catch...catch...finally
**多个异常同时被捕获的时候,记住一个原则:
先逮小的,再逮大的。

**finally:永远被执行,除非退出jvm。System.exit(0);



面试题2个
***:final,finally,finalize区别。
  final是最终的意思。它可以用于修饰类,成员变量,成员方法。
  它修饰的类不能被继承,它修饰的变量时常量,它修饰的方法不能被重写。


  finally:是异常处理里面的关键字

  它其中的代码永远被执行。特殊情况:在执行它之前jvm退出。System.exit(0);

finally代码块只在一种情况下不执行:System.exit(0)



  finalize:是Object类中的一个方法。
  它是于垃圾回收器调用的方式。



***:假如catch中有return语句, finally里中的代码会执行吗?
  是在return前,还是在return后呢?

  会,在return前执行finally里面的代码。


(8)Exception和RuntimeException的区别
A:Exception:一般性的错误,是需要我们编写代码进行处理的。(编译时被检测异常)该异常在编译时,如果没有处理(没有抛,也没有try),编译失败
B:RuntimeException:运行时异常,这个我们也不需要处理。   (编译时不检测)
          其实就是为了让他在运行时出问题,然后我们回来修改代码。
在用throws抛出一个的时候,如果这个异常是属于RuntimeException的体系的时候,
我们在调用的地方可以不用处理。(RuntimeException和RuntimeException的子类)

在用throws抛出一个的时候,如果这个异常是属于Exception的体系的时候,

我们在调用的地方必须进行处理或者继续抛出。


(9)自定义异常
定义类继承Exception或者RuntimeException
1,为了让该自定义类具备可抛性。

2,让该类具备操作异常的共性方法。

如果,在函数内抛出该异常,函数上可以不用声明。

如果,在函数上声明了该异常,调用者可以不进行处理。

当要定义自定义异常的信息时,可以使用父类已经定义好的功能,异常信息传递给父类的构造方法。

class MyExcepiton extends Exception{
	MyExcepiton(){}
	MyExcepiton(String message){
		super(message);
	}
}


class MyException extends RuntimeException{
	MyExcepiton(){}
	MyExcepiton(String message){
		super(message);
	}
}


(10)throws和throw的区别
A:有throws的时候可以没有throw。
  有throw的时候,如果throw抛的异常是Exception体系,那么必须有throws在方法上声明。
B:throws用于方法的声明上,其后跟的是异常类名,后面可以跟多个异常类,之间用逗号隔开

  throw用于方法体中,其后跟的是一个异常对象名

注意:throw后面不要再写语句,(已经结束了)

异常的处理原则:
	1,处理方式有两种:try 或者 throws。
	2,调用到抛出异常的功能时,抛出几个,就处理几个。
		一个try对应多个catch。
	3,多个catch,父类的catch放到最下面。
	4,catch内,需要定义针对性的处理方式。不要简单的定义printStackTrace,输出语句。
		也不要不写。
		当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
		try
		{
			throw new AException();
		}
		catch (AException e)
		{
			throw e;
		}

		如果该异常处理不了,但并不属于该功能出现的异常。
		可以将异常转换后,在抛出和该功能相关的异常。

		或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,
		当调用者知道。并处理。也可以将捕获异常处理后,转换新的异常。
                当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
		try
		{
			throw new AException();
		}
		catch (AException e)
		{
			// 对AException处理。
			throw new BException();
		}

		比如,汇款的例子。

	
异常在子父类覆盖中的体现:
1,子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
2,如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
3,如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
    如果子类方法发生了异常。就必须要进行try处理。绝对不能抛。

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值