黑马程序员-----JAVA面向对象(三)

                ---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

模板方法设计模式:

解决的问题:当功能内部一部分实现时确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

abstract class GetTime{
    public finalvoid getTime(){ //此功能如果不需要复写,可加final限定
        long start =System.currentTimeMillis();
        code(); //不确定的功能部分,提取出来,通过抽象方法实现
        long end = System.currentTimeMillis();
        System.out.println("毫秒是:"+(end-start));
    }
    public abstract void code(); //抽象不确定的功能,让子类复写实现
}
class SubDemo extends GetTime{
    public void code(){ //子类复写功能方法
        for(int y=0;y<1000; y++){
            System.out.println("y");
        }
    }
}

接 口:

1:是用关键字interface定义的。

2:接口中包含的成员,最常见的有全局常量、抽象方法。

注意:接口中的成员都有固定的修饰符。

    成员变量:public static final

    成员方法:public abstract

interface Inter{
    publicstatic final int x = 3;
    publicabstract void show();
}

3:接口中有抽象方法,说明接口不可以实例化接口的子类必须实现了接口中所有的抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。

4:类与类之间存在着继承关系,类与接口中间存在的是实现关系。

    继承用extends  ;实现用implements ;

5:接口和类不一样的地方,就是,接口可以被多实现,这就是多继承改良后的结果。java将多继承机制通过多现实来体现。

6:一个类在继承另一个类的同时,还可以实现多个接口。所以接口的出现避免了单继承的局限性。还可以将类进行功能的扩展。

7:其实java中是有多继承的。接口与接口之间存在着继承关系,接口可以多继承接口

接口都用于设计上,设计上的特点:(可以理解主板上提供的接口)

1:接口是对外提供的规则。

2:接口是功能的扩展。

3:接口的出现降低了耦合性。 

抽象类与接口:

抽象类:一般用于描述一个体系单元,将一组共性内容进行抽取,特点:可以在类中定义抽象内容让子类实现,可以定义非抽象内容让子类直接使用。它里面定义的都是一些体系中的基本内容。

接口:一般用于定义对象的扩展功能,是在继承之外还需这个对象具备的一些功能。

抽象类和接口的共性:都是不断向上抽取的结果。

抽象类和接口的区别:

1:抽象类只能被继承,而且只能单继承;

      接口需要被实现,而且可以多实现。

2:抽象类中可以定义非抽象方法,子类可以直接继承使用;

      接口中都有抽象方法,需要子类去实现。

3:抽象类使用的是  is a 关系;

     接口使用的 like a 关系。

4:抽象类的成员修饰符可以自定义;

      接口中的成员修饰符是固定的。全都是public的。

 在开发之前,先定义规则,A和B分别开发,A负责实现这个规则,B负责使用这个规则。至于A是如何对规则具体实现的,B是不需要知道的。这样这个接口的出现就降低了A和B直接耦合性。

/*
笔记本电脑使用。
为了扩展笔记本的功能,但日后出现什么功能设备不知道。
定义一个规则,只要日后出现的设备都符合这个规则就可以了。
规则在java中就是接口。
*/
interface USB// 暴露的规则。
{
	public void open();
	public void close();
}
class BookPC
{
	public static void main(String[] args)
	{
		useUSB(new UPan());//功能扩展了。
		useUSB(new UsbMouse());
	}

	//使用规则。
	public static void useUSB(USB u)//接口类型的引用,用于接收(指向)接口的子类对象。//USB u= new UPan();
	{
		if(u!=null)
		{
			u.open();
			u.close();
		}
	}
}
//一年后
//实现规则。
//这些设备和电脑的耦合性降低了。
class UPan implements USB
{
	public void open()
	{
		System.out.println("upan open");
	}
	public void close()
	{
		System.out.println("upan close");
	}

}
class UsbMouse implements USB
{
	public void open()
	{
		System.out.println("UsbMouse open");
	}
	public void close()
	{
		System.out.println("UsbMouse close");
	}

}

多 态:函数本身就具备多态性,某一种事物有不同的具体的体现。

体现:父类引用或者接口的引用指向了自己的子类对象。//Animal a = newCat();

多态的好处:提高了程序的扩展性。

多态的弊端:当父类引用指向子类对象时,虽然提高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。(前期不能使用后期产生的功能,即访问的局限性)

多态的前提:

    1:必须要有关系,比如继承、或者实现。

    2:通常会有覆盖操作。

 

多态的出现思想上也做着变化:以前是创建对象并指挥对象做事情。有了多态以后,我们可以找到对象的共性类型,直接操作共性类型做事情即可,这样可以指挥一批对象做事情,即通过操作父类或接口实现。

/*
毕老师和毕姥爷的故事。
*/
class 毕姥爷
{
	void 讲课()
	{
		System.out.println("管理");
	}
	void 钓鱼()
	{
		System.out.println("钓鱼");
	}
}
class 毕老师 extends 毕姥爷
{
	void 讲课()
	{
		System.out.println("Java");
	}
	void 看电影()
	{
		System.out.println("看电影");
	}
}
class  DuoTaiDemo2
{
	public static void main(String[] args) 
	{
		毕姥爷 x = new 毕老师();//毕老师对象被提升为了毕姥爷类型。
		x.讲课();
		x.钓鱼();
		毕老师 y = (毕老师)x;//将毕姥爷类型强制转换成毕老师类型。
		y.看电影();//在多态中,自始自终都是子类对象在做着类型的变化。	
	}
}

如果想用子类对象的特有方法,如何判断对象是哪个具体的子类类型呢?

可以可以通过一个关键字instanceof;//判断对象是否实现了指定的接口或继承了指定的类

 

格式:<对象 instanceof 类型> ,判断一个对象是否所属于指定的类型。

Student instanceof Person =true;//student继承了person类

 

多态在子父类中的成员上的体现的特点:

1,成员变量:在多态中,子父类成员变量同名。

    在编译时期:参考的是引用型变量所属的类中是否有调用的成员。(编译时不产生对象,只检查语法错误

    运行时期:也是参考引用型变量所属的类中是否有调用的成员。

    简单一句话:无论编译和运行,成员变量参考的都是引用变量所属的类中的成员变量。

    再说的更容易记忆一些:成员变量 --- 编译运行都看 = 左边。

2,成员函数。

    编译时期:参考引用型变量所属的类中是否有调用的方法。

    运行事情:参考的是对象所属的类中是否有调用的方法。

    为什么是这样的呢?因为在子父类中,对于一模一样的成员函数,有一个特性:覆盖。

    简单一句:成员函数,编译看引用型变量所属的类,运行看对象所属的类。

    更简单:成员函数 --- 编译看 = 左边,运行看= 右边。

3,静态函数。

    编译时期:参考的是引用型变量所属的类中是否有调用的成员。

    运行时期:也是参考引用型变量所属的类中是否有调用的成员。

    为什么是这样的呢?因为静态方法,其实不所属于对象,而是所属于该方法所在的类。

    调用静态的方法引用是哪个类的引用调用的就是哪个类中的静态方法。

    简单说:静态函数 --- 编译运行都看 = 左边。

class Fu
{
	void show()
	{
		System.out.println("fu show");
	}
	static void method()
	{
		System.out.println("fu static method");
	}
}
class Zi extends Fu
{
	void show()
	{
		System.out.println("zi show");
	}

	static void method()
	{
		System.out.println("zi static method");
	}
}
class  DuoTaiDemo3
{
	public static void main(String[] args) 
	{
		Fu.method();
		Zi.method();
		Fu f = new Zi();
	}
}

Object:所有类的直接或者间接父类,Java认为所有的对象都具备一些基本的共性内容,这些内容可以不断的向上抽取,最终就抽取到了一个最顶层的类中的,该类中定义的就是所有对象都具备的功能。

 具体方法:

1,boolean equals(Object obj):用于比较两个对象是否相等,其实内部比较的就是两个对象地址。

而根据对象的属性不同,判断对象是否相同的具体内容也不一样。所以在定义类时,一般都会复写equals方法,建立本类特有的判断对象是否相同的依据。

public boolean equals(Object obj){
      if(!(obj instanceof Person))
          return false;
      Person p = (Person)obj;
      return this.age == p.age;
  }

2,String toString():将对象变成字符串;默认返回的格式:类名@哈希值 = getClass().getName() + '@' + Integer.toHexString(hashCode())

  为了对象对应的字符串内容有意义,可以通过复写,建立该类对象自己特有的字符串表现形式。

public String toString(){
      return "person : "+age;
  }

3,Class getClass():获取任意对象运行时的所属字节码文件对象。

4,int hashCode():返回该对象的哈希码值。支持此方法是为了提高哈希表的性能。

 通常equals,toString,hashCode,在应用中都会被复写,建立具体对象的特有的内容。


内部类:如果A类需要直接访问B类中的成员,而B类又需要建立A类的对象。这时,为了方便设计和访问,直接将A类定义在B类中。就可以了。A类就称为内部类。内部类可以直接访问外部类中的成员。而外部类想要访问内部类,必须要建立内部类的对象。

class Outer{
    int num = 4;   
    class  Inner {
        void show(){
            System.out.println("innershow run "+num);         
        }
    }
    public void method(){
        Inner in = newInner();//创建内部类的对象。
        in.show();//调用内部类的方法。
    }
}

当内部类定义在外部类中的成员位置上,可以使用一些成员修饰符修饰 private、static。

1:默认修饰符。

直接访问内部类格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象;

Outer.Inner in = new Outer.new Inner();//这种形式很少用。

  但是这种应用不多见,因为内部类之所以定义在内部就是为了封装。想要获取内部类对象通常都通过外部类的方法来获取。这样可以对内部类对象进行控制。

2:私有修饰符。

  通常内部类被封装,都会被私有化,因为封装性不让其他程序直接访问。

3:静态修饰符。

  如果内部类被静态修饰,相当于外部类,会出现访问局限性,只能访问外部类中的静态成员。

  注意;如果内部类中定义了静态成员,那么该内部类必须是静态的。

 

内部类编译后的文件名为:“外部类名$内部类名.java”;

 

为什么内部类可以直接访问外部类中的成员呢?

那是因为内部中都持有一个外部类的引用。这个是引用是 外部类名.this

内部类可以定义在外部类中的成员位置上,也可以定义在外部类中的局部位置上。

当内部类被定义在局部位置上,只能访问局部中被final修饰的局部变量。

 匿名内部类:没有名字的内部类。就是内部类的简化形式。一般只用一次就可以用这种形式。匿名内部类其实就是一个匿名子类对象想要定义匿名内部类:需要前提,内部类必须继承一个类或者实现接口。

 匿名内部类的格式:new 父类名&接口名(){ 定义子类成员或者覆盖父类方法 }.方法。

 匿名内部类的使用场景:

当函数的参数是接口类型引用时,如果接口中的方法不超过3个。可以通过匿名内部类来完成参数的传递。

其实就是在创建匿名内部类时,该类中的封装的方法不要过多,最好两个或者两个以内。

class Outer
{
	void method()
	{
		Object obj = new Object()
		{	public void show()
			{
				System.out.println("show run");
			}
		};
		obj.show();//因为匿名内部类这个子类对象被向上转型为了Object类型。
					//这样就不能在使用子类特有的方法了。
	}
}
class InnerClassDemo6 
{
	public static void main(String[] args) 
	{
		new Outer().method();
	}
}

interface Inter
{	void show1();
	void show2();
}
class Outer
{	public void method()
	{	Inter in = new Inter()
		{
			public void show1()
			{}
			public void show2()
			{}			
		};
		in.show1();
		in.show2();
	}
}
/*
通常的使用场景之一:
当函数参数是接口类型时,而且接口中的方法不超过三个。
可以用匿名内部类作为实际参数进行传递
*/
class InnerClassDemo5 
{
	class Inner
	{
	}
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
	public void method()
	{
		new Inner();
	}
	public static void show(Inter in)
	{
		in.show1();
		in.show2();
	}
}
异 常:

异常:就是不正常。程序在运行时出现的不正常情况。其实就是程序中出现的问题。这个问题按照面向对象思想进行描述,并封装成了对象。因为问题的产生有产生的原因、有问题的名称、有问题的描述等多个属性信息存在。当出现多属性信息最方便的方式就是将这些信息进行封装。异常就是java按照面向对象的思想将问题进行对象封装。这样就方便于操作问题以及处理问题。

 

出现的问题有很多种,比如角标越界,空指针等都是。就对这些问题进行分类。而且这些问题都有共性内容比如:每一个问题都有名称,同时还有问题描述的信息,问题出现的位置,所以可以不断的向上抽取。形成了异常体系

Throwable:可抛出的。

    |--Error:错误,一般情况下,不编写针对性的代码进行处理,通常是jvm发生的,需要对程序进行修正。

    |--Exception:异常,可以有针对性的处理方式

 

无论是错误还是异常,它们都有具体的子类体现每一个问题,它们的子类都有一个共性,就是都以父类名才作为子类的后缀名

 这个体系中的所有类和对象都具备一个独有的特点;就是可抛性

可抛性的体现:就是这个体系中的类和对象都可以被throws和throw两个关键字所操作。

class  ExceptionDemo{
    public static voidmain(String[] args) {
//      byte[] buf = newbyte[1024*1024*700];//java.lang.OutOfMemoryError内存溢出错误
    }
}
在开发时,如果定义功能时,发现该功能会出现一些问题, 应该将问题在定义功能时标示出来,这样调用者就可以在使用这个功能的时候,预先给出处理方式。

 

如何标示呢?通过throws关键字完成,格式:throws 异常类名,异常类名...

这样标示后,调用者,在使用该功能时,就必须要处理,否则编译失败。

 

处理方式有两种:1、捕捉;2、抛出。

对于捕捉:java有针对性的语句块进行处理。

try {

    需要被检测的代码;

}

catch(异常类 变量名){

    异常处理代码;

}

fianlly{

    一定会执行的代码;

}

catch (Exception e) { //e用于接收try检测到的异常对象。
    System.out.println("message:"+e.getMessage());//获取的是异常的信息。
    System.out.println("toString:"+e.toString());//获取的是异常的名字+异常的信息。
    e.printStackTrace();//打印异常在堆栈中信息;异常名称+异常信息+异常的位置。
}
异常处理原则:功能抛出几个异常,功能调用如果进行try处理,需要与之对应的catch处理代码块,这样的处理有针对性,抛几个就处理几个。

 特殊情况:try对应多个catch时,如果有父类的catch语句块,一定要放在下面。

 throw 和throws关键字的区别:

throw用于抛出异常对象,后面跟的是异常对象;throw用在函数内。

throws用于抛出异常类,后面跟的异常类名,可以跟多个,用逗号隔开。throws用在函数上。

 

通常情况:函数内容如果有throw,抛出异常对象,并没有进行处理,那么函数上一定要声明,否则编译失败。但是也有特殊情况。

 异常分两种:

1:编译时被检查的异常,只要是Exception及其子类都是编译时被检测的异常。

2:运行时异常,其中Exception有一个特殊的子类RuntimeException,以及RuntimeException的子类是运行异常,也就说这个异常是编译时不被检查的异常。

 编译时被检查的异常和运行时异常的区别:

编译被检查的异常在函数内被抛出,函数必须要声明,否编译失败。

声明的原因:是需要调用者对该异常进行处理。

运行时异常如果在函数内被抛出,在函数上不需要声明。

不声明的原因:不需要调用者处理,运行时异常发生,已经无法再让程序继续运行,所以,不让调用处理的,直接让程序停止,由调用者对代码进行修正。

定义异常处理时,什么时候定义try,什么时候定义throws呢?

功能内部如果出现异常,如果内部可以处理,就用try;

如果功能内部处理不了,就必须声明出来,让调用者处理。

 自定义异常:当开发时,项目中出现了java中没有定义过的问题时,这时就需要我们按照java异常建立思想,将项目的中的特有问题也进行对象的封装。这个异常,称为自定义异常。

 对于除法运算,0作为除数是不可以的。java中对这种问题用ArithmeticException类进行描述。对于这个功能,在我们项目中,除数除了不可以为0外,还不可以为负数。可是负数的部分java并没有针对描述。所以我们就需要自定义这个异常。

 自定义异常的步骤:

1:定义一个子类继承Exception或RuntimeException,让该类具备可抛性。

2:通过throw 或者throws进行操作。

 异常的转换思想:当出现的异常是调用者处理不了的,就需要将此异常转换为一个调用者可以处理的异常抛出。 

try  catch finally的几种结合方式:

1.try             2.try                 3.try

   catch            finally            catch

                                            finally

这种情况,如果出现异常,并不处理,但是资源一定关闭,所以try  finally集合只为关闭资源

注意:finally很有用,主要用户关闭资源。无论是否发生异常,资源都必须进行关闭。

System.exit(0); //退出jvm,只有这种情况finally不执行。

当异常出现后,在子父类进行覆盖时,有了一些新的特点:

1:当子类覆盖父类的方法时,如果父类的方法抛出了异常,那么子类的方法要么不抛出异常要么抛出父类异常或者该异常的子类,不能抛出其他异常。

2:如果父类抛出了多个异常,那么子类在覆盖时只能抛出父类的异常的子集。

注意:

如果父类或者接口中的方法没有抛出过异常,那么子类是不可以抛出异常的,如果子类的覆盖的方法中出现了异常,只能try不能throws。

如果这个异常子类无法处理,已经影响了子类方法的具体运算,这时可以在子类方法中,通过throw抛出RuntimeException异常或者其子类,这样,子类的方法上是不需要throws声明的。

 

常见异常:

1、脚标越界异常(IndexOutOfBoundsException)包括数组、字符串;

空指针异常(NullPointerException)

2、类型转换异常:ClassCastException

3、没有这个元素异常:NullPointerException

4、不支持操作异常;

异常要尽量避免,如果避免不了,需要预先给出处理方式。比如家庭备药,比如灭火器。

/*
毕老师用电脑上课。

问题领域中涉及两个对象。
毕老师,电脑。

分析其中的问题。

比如电脑蓝屏啦。冒烟啦。

*/

class LanPingException extends Exception
{
	LanPingException(String msg)
	{
		super(msg);
	}
}

class MaoYanException extends Exception
{
	MaoYanException(String msg)
	{
		super(msg);
	}
}

class NoPlanException extends Exception
{
	NoPlanException(String msg)
	{
		super(msg);
	}
}

class Computer
{
	private int state = 2;
	public void run()throws LanPingException,MaoYanException
	{
		if(state==1)
			throw new LanPingException("电脑蓝屏啦!!");
		if(state==2)
			throw new MaoYanException("电脑冒烟啦!!");

		System.out.println("电脑运行");
	}
	public void reset()
	{
		state = 0;
		System.out.println("电脑重启");
	}
}

class Teacher
{
	private String name;
	private Computer comp;
	Teacher(String name)
	{
		this.name = name;
		comp = new Computer();
	}
	
	public void prelect()throws NoPlanException
	{
		try
		{
			comp.run();
			System.out.println(name+"讲课");
			
		}
		catch (LanPingException e)
		{
			System.out.println(e.toString());
			comp.reset();
			prelect();
		}
		catch (MaoYanException e)
		{
			System.out.println(e.toString());
			test();
			//可以对电脑进行维修。
			throw new NoPlanException("课时进度无法完成,原因:"+e.getMessage());
		}

	}
	public void test()
	{
		System.out.println("大家练习");
	}
}	
class ExceptionTest 
{
	public static void main(String[] args) 
	{
		Teacher t  = new Teacher("毕老师");
		try
		{
			t.prelect();
			
		}
		catch (NoPlanException e)
		{
			System.out.println(e.toString()+"......");
			System.out.println("换人");

		}
	}
}

包:定义包用package关键字。

1:对类文件进行分类管理。

2:给类文件提供多层名称空间。

 

如果生成的包不在当前目录下,需要最好执行classpath,将包所在父目录定义到classpath变量中即可。

一般在定义包名时,因为包的出现是为了区分重名的类。所以包名要尽量唯一。怎么保证唯一性呢?可以使用url域名来进行包名称的定义。

package pack;//定义了一个包,名称为pack。注意:包名的写法规范:所有字母都小写。

//packagecn.itcast.pack.demo;

类的全名称是 包名.类名

    编译命令:javac –d位置(.当前路径) java源文件 (就可以自动生成包)

包是一种封装形式,用于封装类,想要被包以外的程序访问,该类必须public;

类中的成员,如果被包以外访问,也必须public;

包与包之间访问可以使用的权限有两种:

1:public

2:protected:只能是不同包中的子类可以使用的权限。

 总结java中的四种权限:

 黑马程序员-----JAVA面向对象(三)_第1张图片

Import - 导入:类名称变长,写起来很麻烦。为了简化,使用了一个关键字:import,可以使用这个关键字导入指定包中的类。记住:实际开发时,到的哪个类就导入哪个类,不建议使用*.

import packa.*;//这个仅仅是导入了packa当前目录下的所有的类。不包含子包。

importpacka.abc.*;//导入了packa包中的子包abc下的当前的所有类。

如果导入的两个包中存在着相同名称的类。这时如果用到该类,必须在代码中指定包名。

常见的软件包:

java.lang :language java的核心包,ObjectSystem  String Throwable jdk1.2版本后,该包中的类自动被导入。

java.awt : 定义的都是用于java图形界面开发的对象。

javax.swing: 提供所有的windows桌面应用程序包括的控件,比如:Frame , Dialog, Table, List 等等,就是java的图形界面库。

java.net : 用于java网络编程方面的对象都在该包中。

java.io :input  output 用于操作设备上数据的对象都在该包中。比如:读取硬盘数据,往硬盘写入数据。

java.util :java的工具包,时间对象,集合框架。

java.applet:application+let 客户端java小程序。server+let  -->  servlet 服务端java小程序。 

jar :java的压缩包,主要用于存储类文件,或者配置文件等。

命令格式:jar –cf 包名.jar 包目录

   解压缩:jar –xvf 包名.jar

 将jar包目录列表重定向到一个文件中:jar –tf 包名.jar >c:\1.txt

                ---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

你可能感兴趣的:(JAVA学习笔记)