java学习-面向对象

一、java中的成员变量与局部变量
1、定义
(1)成员变量:在类定义中,用来描述对象拥有的属性
(2)局部变量:在类的方法中定义,在方法中临时保存数据
2、区别
(1)作用域不同
局部变量作用于仅限于定义它的方法内
成员变量若为公共的,则在类外也可以被使用;若定义为私有的,则只能通过类中调用该私有变量的方法调用
(2)初始值不同
在java中,成员变量有默认初始值,但局部变量没有默认初始值
(3)在java中,统一方法内不能有同名的局部变量。在不同的方法中,可以有重名的局部变量
(4)成员变量与局部变量重名时,在局部变量作用范围内,局部变量优先。
二、java中的static
1、静态成员变量
java中被static修饰的成员变量称为静态成员变量,其属于整个类所有,在类加载时加载,不需要建立对象调用。静态成员变量可以使用类名直接访问,也可以用对象名访问。
2、静态方法
定义功能时,如果功能不需要访问类中定义的成员变量(非静态)时,该功能就需要静态修饰。
(1)静态方法可以调用同类的静态成员,但是不能直接调用非静态成员,但是非静态方法可以访问静态成员。
(2)若希望在静态方法中调用非静态成员,可以创建类的对象,然后通过对象来访问非静态成员
(3)在普通成员方法中,可以直接访问同类的非静态变量和静态变量
(4)静态是随着类的加载就加载了,也是随着类的消失而消失了。
(5)静态优先于对象存在,被对象共享。
(6)静态方法中不允许出现this,super关键字。
因为静态先存在于内存中无法访问后来的对象的中的数据,所以静态无法访问非静态。而且内部无法书写this,因为这时对象有可能不存在,this没有任何指向。
静态的弊端在于访问出现局限性。好处是可以直接被类名调用。
3、静态代码块
类一加载,需要做一些动作。不一定需要对象。
(1)特点:随着类的加载而执行,仅执行一次。
(2)作用:给类进行初始化。

class Demo
{
	static int x = 9;//静态变量有两次初始化。 一次默认初始化,一次显示初始化。
	static //静态代码块。在静态变量显示初始化以后在执行。
	{
		System.out.println("类加载就执行的部..."+x);
	}
	static void show()
	{
		System.out.println("show run");
	}
}	

class StaticCodeDemo 
{
	public static void main(String[] args) 
	{
		Demo.show();
		Demo.show();
	}
}

三、对象的初始化过程
1、加载Demo.class文件进方法区,并进行空间分配。
2、如果有静态变量,先默认初始化,显示初始化。
3、如果有静态代码块,要执行,仅一次。
4、通过new在堆内存中开辟空间,并明确首地址。
5、对对象中的属性进行默认初始化。
6、调用对应的构造函数进行初始化。
7、构造函数内部。
(1)调用父类构造函数super();
(2)成员变量的显示初始化。
(3)构造代码块初始化。
(4)构造函数内容自定义内容初始化。
8、对象初始化完毕后,将地址赋值给引用变量。
四、封装
1、作用
隐藏式西安西郊,对外提供公共接口。
此接口并不是指interface接口,而是指程序对外暴漏的公共端口。
2、封装步骤
(1)修改属性的可见性
(2)创建get/set等可用于操作属性的方法
(3)在相关方法中加入属性控制语句,对属性值的合法性进行判断
五、单例设计模式
1、作用
保证一个类的对象的唯一性
2、应用场景
比如当多个程序都要使用一个配置文件中的数据,而且要实现数据共享和交换。必须要将多个数据封装到一个对象中。而且多个程序操作的是同一个对象。那也就是说必须保证这个配置文件对象的唯一性。
2、设计思路
如何保证唯一性。
(1)为避免其他程序建立过多的该类对象,应先禁止其他程序建立该类对象。
将该类的构造函数私有化,禁止外界创建该类对象
(2)为了让其它程序可以访问到该类对象,必须在本类中自定义一个对象
在本类中创建一个本类对象
(3)为方便其他程序自自定义对象的访问,可以对外提供一些访问方式
提供一个方法可以获取该类对象
3、使用方式
对事物该怎么描述就怎么描述。当需要该对象保证唯一性时,按照以上三步进行
(1)饿汉式

class Single
{
	//2,创建一个本类对象。
	private static /*final*/ Single s = new Single();

	//1,私有化构造函数。
	private Single(){}

	//3,定义一个方法返回这个对象。
	public static Single getInstance()
	{
		return s;
	}
}

(2)懒汉式
单例的延迟加载方式。面试最多的是懒汉式。

class Demo
{
	static int x = 9;//静态变量有两次初始化。 一次默认初始化,一次显示初始化。
	static //静态代码块。在静态变量显示初始化以后在执行。
	{
		System.out.println("类加载就执行的部..."+x);
	}
	static void show()
	{
		System.out.println("show run");
	}
}	

class StaticCodeDemo 
{
	public static void main(String[] args) 
	{
		Demo.show();
		Demo.show();
	}
}

六、继承 extends
1、作用
提高代码的复用性,并让对象间产生关系,为多态做前提
2、继承的初始化顺序
(1)先初始化父类,在初始化子类
(2)先执行初始化对象中的属性,在执行构造该方法中的初始化
3、final关键字
(1) 使用final关键字做标识,有最终的含义
(2)final可以修饰类、方法、属性和变量
①final修饰类,则该类不允许被继承
②final修饰方法,则该类不能被子类覆盖(重写)
③final修饰属性,则该属性不能隐式初始化,在初始化时,属性必须有值,即在构造函数中赋值
④final修饰变量,则该变量只能被赋值一次,称为常量
4、super关键字
常在对象内部使用,代表父类对象
(1)访问父类的属性
(2)调用父类的方法
(3)子类的构造函数中必须调用父类的构造方法。若子类显式的调用父类的构造方法,则super()必须放在子类构造函数的第一行。
5、Object类
(1)Object类是所有类的父类
(2)Object类中的方法适合所有类
(3)toString( )方法。返回的是关于对象地址的哈希code码,用字符串表示
(4)equals( ) 方法
比较的是对象的引用是否指向同一个内存地址
七、抽象类
1、定义
(1)用abstract修饰
(2)在描述事物时,没有足够的信息描述一个事物,这时该事物就是抽象事物。
2、抽象类的特点
(1)抽象类和抽象方法都需要被abstract修饰。
(2)抽象方法一定要定义在抽象类中。
(3)抽象类不可以创建实例,原因:调用抽象方法没有意义。
(4)只有覆盖了抽象类中所有的抽象方法后,其子类才可以实例化。否则该子类还是一个抽象类。
3、注意事项
(1)抽象类一定是个父类,因为其是不断抽取而来的。
(2)抽象类有构造函数。
虽然不能给自己的对象初始化,但是可以给自己的子类对象初始化。
(3)抽象类中是否可以不定义抽象方法。
是可以的,那这个抽象类的存在到底有什么意义呢?仅仅是不让该类创建对象
(4)抽象关键字abstract不可以和哪些关键字共存?
1,final:
2,private:
3,static:
4、抽象类和一般类的异同点:
(1)相同:
①它们都是用来描述事物的。
②它们之中都可以定义属性和行为。
(2)不同:
①一般类可以具体的描述事物。
②抽象类描述事物的信息不具体
③抽象类中可以多定义一个成员:抽象函数。
④一般类可以创建对象,而抽象类不能创建对象。
八、接口 Interface
1、接口的由来
当一个抽象类中的方法全是抽象的,此抽象类可定义为接口
2、定义
接口的定义格式
(1)定义变量
但是变量必须有固定的修饰符修饰,public static final 所以接口中的变量也称之为常量。
(2)定义方法
方法也有固定的修饰符,public abstract
接口中的成员都是公共的。

interface Demo
{
	public static final int NUM = 3;
	public abstract void show1();
	public abstract void show2();
}

3、特点
(1)接口不可以创建对象。
(2)子类必须覆盖掉接口中所有的抽象方法后,子类才可以实例化,否则子类是一个抽象类。
(3)解决多继承的弊端,将多继承这种机制在java中通过多实现完成了。
4、子类实现接口 implements
定义子类去覆盖接口中的方法。子类必须和接口产生关系,类与类的关系是继承,类与接口之间的关系是 实现。通过 关键字 implements

class DemoImpl implements Demo//子类实现Demo接口。
{
	//重写接口中的方法。
	public void show1(){}
	public void show2(){}
}

5、弊端
多继承时,当多个父类中有相同功能时,子类调用会产生不确定性。其实核心原因就是在于多继承父类中功能有主体,而导致调用运行时,不确定运行哪个主体内容。
而接口中的功能都没有方法体,由子类来明确。
6、接口和父类的区别
(1)子类通过继承父类扩展功能,通过继承扩展的功能都是子类应该具备的基础功能。如果子类想要继续扩展其他类中的功能呢?这时通过实现接口来完成。
(2)接口的出现避免了单继承的局限性。
(3)父类中定义的事物的基本功能,接口中定义的事物的扩展功能。
(4)类与类之间是继承(is a)关系,类与接口之间是实现(like a)关系。
(5)接口与接口之间是继承关系,而且可以多继承。
7、没有抽象方法的抽象类
为了使用接口中的部分方法。而覆盖了全部的方法,而且每一个子类都要这么做,复用性差。将这些不用的方法都单独抽取到一个独立的类中。让这个类去实现接口,并覆盖接口中的所有方法。
这个类不知道这些方法的具体实现内容,只为了后期子类创建对象方便,而进行空实现。此时创建该类对象没有意义,直接将其抽象化。
这就是没有抽象方法的抽象类。

*/
abstract class InterImpl implements Inter
{
	//实现Inter接口中的所有方法。
	public void show1(){}
	public void show2(){}
	public void show3(){}
	public void show4(){}
}
//如果有子类去使用显示1方法。让子类继承InterImpl实现类就可以了。
class InterImpl11 extends InterImpl
{
	public void show1()
	{
		System.out.println("show1 run");
	}
}

九、多态
1、定义
对象具有的多种形态
2、前提
(1)继承是多态的基础
(2)通常有重写操作
3、类型
(1)应用多态
父类引用既可指向父类对象,又可指向子类对象
(2)方法多态
①父类引用创建父类对象时,调用的方法为父类方法
②父类引用创建子类对象时,父类引用调用的方法为子类重写的方法或继承的方法
4、多态中成员调用特点
Fu a = new Zi( );
(1)成员变量
当子父类中出现同名的成员变量时,多态调用该变量时:编译时期,此时还没有创建对象,JVM参考的是引用类型变量所在的类之中是否有该变量,若有,则编译通过;若没有则编译失败。在运行时期,也是调用引用类型变量所属类中的成员变量。
简单记:编译和运行都参考等号左边
(2)成员函数
编译时参考左边,如果左边的类中有该方法,则编译通过,否则编译失败。运行时,由于父类引用指向的是子类的对象,子类对象对父类的同名函数进行了重写,因此父类引用调用该函数时,实际是调用子类的函数。
即:编译看左边,运行看右边
(3)静态函数
编译和运行只看左边
因为静态函数在类加载时就存在,与具体的对象无关。当调用静态函数时,其只调用该静态函数的类中的静态方法
结论:
对于成员变量和静态函数,编译和运行时看左边
对于成员函数,编译时看左边,运行时看右边
5.多态中引用类型转换
(1)向上转换
父类型引用指向子类对象时,这就是让子类对象进行了类型的提升(向上转型)。
好处:提高了扩展性,隐藏了子类型。
弊端:不能使用子类型的特有方法。
(2)向下转换
当需要使用子类型的特有内容时,可以向下转型,强制转换。
向下转型的注意事项:
向下转型因为不明确具体子类对象类型,所以容易引发ClassCastException异常。 所以为了避免这个问题,在向下转型前,需要做类型的判断。 判断类型用的是关键字 instanceof
if(a instanceof B) :a引用指向的对象的类型为B类型,则为true
十、内部类
1、定义
当A类中的内容要被B类直接访问,而A类还需要创建B的对象,访问B的内容。这时,可以将B类定义到A类的内部。B类称之为内部类(内置类,嵌套类)。
2、访问方式
内部类可以直接访问外部类中的所有成员,包含私有的。而外部类要想访问内部类中的成员,必须创建内部类的对象。
当描述事物时,事物的内部还有事物,这个内部的事物还在访问外部事物中的内容。这时就将这个内部事物通过内部类来描述。
(1)情况一:内部类在成员位置上的被访问方式。
成员是可以被指定的修饰符所修饰的。 public不多见:因为更多的时候,内部类已经被封装到了外部类中,不直接对外提供。
注意:
①非静态内部类中不允许定义静态成员。仅允许在非静态内部类中定义静态常量 static final。
②如果想要在内部类中定义静态成员,必须内部类也要被静态修饰。
③当内部类被静态修饰后,随着外部类的加载而加载。可以把一个静态内部类理解为就是一个外部类
⑤内部类作为成员,应该先有外部类对象,再有内部类对象。
⑥如果静态内部类有静态成员,由于静态内部类已随外部类加载,而且静态成员随着类的加载而加载,就不需要对象,直接用类名调用

class Outer//外部类。
{
	private static int num = 4;
	public class Inner	//内部类。
	{
		void show()
		{
			System.out.println("num="+num);
		}

	}
	static class Inner2
	{
		void show2()
		{
			System.out.println("Inner2 show2 run..."+num);
		}
		static void staticShow()
		{
			System.out.println("Inner2 staticShow run");
		}
	}
	void method()
	{
		/*Outer.*/Inner in = new /*Outer.*/Inner();
		in.show();
	}
}

(3)内部类访问外部类原理
因为内部类其实持有了外部类的引用 外部类.this ,对于静态内部类不持有 外部类.this 而是直接使用 外部类名。
3、内部类作为局部变量
内部类定义在局部时,只能访问被final修饰的局部变量。因为内部类编译生产的class中直接操作的是最终数值,不允许改变其调用的变量内容。
4、内部类的延伸
内部类是可以继承或者实现外部其他的类或者接口的。
好处:通过内部类的方式对类进行继承重写,或者接口进行实现。
通过公共的方式对其内部类对象进行访问。因为通常内部类很有可能被外部类封装其中,可以通过父类或者接口的方式访问到内部类对象。

abstract class AbsDemo	//外面的类
{
	abstract void show();
}

class Outer
{
	int num = 3;
	private class Inner extends AbsDemo	//内部类实现了外面的类的功能
	{
		void show()
		{
			System.out.println("num="+num);
		}
	}
	//获取内部类的对象。 
	public AbsDemo getObject()
	{
		return new Inner();
	}
	public void method()
	{
		new Inner().show();
	}
}

class InnerClassDemo4 
{
	public static void main(String[] args) 
	{
		Outer out = new Outer();
		//如果Inner对外提供,可以直接创建内部类对象获取。
//		Outer.Inner in = out.getObject();
//		in.show();
		//如果Inner被private ,则不能通过外部类实例化,此时可以内部内对象可以通过父类型获取。
		AbsDemo a = out.getObject();//多态。
		a.show();
	}
}

5、匿名内部类
(1)其实就是一个带有内容的子类对象。
(2)格式:
new 父类or接口( ){ 子类的内容 }
(3)匿名内部类就是内部类的简化形式。
(4)使用匿名内部类有前提,内部类必须要继承父类或者实现接口

class Outer2
{
	public void method()
	{
		//以下两个对象有区别吗?
		new Object()
		{
			public void show(){}
		}.show();//这个可以编译通过。

		Object obj = new Object()
		{
			public void show(){}
		};
obj.show();
//编译失败。为啥呢?因为匿名内部类是子类对象,当Object obj指向时,就被提升了Object。而Object
//类中没有定义show方法,编译失败。
}

十一、异常
1、定义
Java运行时期发生的问题就是异常。
2、异常Exception和错误Error
Java中运行时发生的除了异常Exception还有错误Error。
异常:通常发生可以有针对性的处理方式的。
错误:通常发生后不会有针对性的处理方式。因为是系统底层发生,必须修改代码。
Error的发生往往都是系统级别的问题,都是jvm所在系统发生的并反馈给jvm的,无法针对处理,只能修正代码。
3、异常的抛出:throw 与 throws
throw:写在方法体内,将产生的异常抛出
throws:写在方法名后,参数列表前
在编写程序时,必须要考虑程序的问题情况,所以定义定义程序需要考虑程序的健壮性。可以加入一些逻辑性的判断,当程序出现问题时,就必须结束功能,并将问题告知给调用者。通过异常来解决:
(1)创建一个异常对象。封装一些提示信息(自定义)。
(2)通过关键字throw,将异常信息抛出,告知给调用者
(3)throw用在函数内,抛出异常对象,并可以结束函数。
4、自定义异常
(1)自定义异常就是将具体遇到的问题封装成了异常对象。
(2)格式
自定义异常被抛出,必须是继承Throwable,或者继承Throwable的子类,该对象才可以被throw抛出。
class 自定义异常 extends 异常类
{
}
(3)自定义异常。描述Person的年龄数值非法。

class NoAgeException extends RuntimeException
{
	/*
	为什么要定义构造函数,因为看到Java中的异常描述类中有提供对问题对象的初始化方法。
	*/
	NoAgeException()
	{
		super();
	}

	NoAgeException(String message)
	{
		super(message);// 如果自定义异常需要异常信息,可以通过调用父类的带有字符串参数的构造函数即可。
	}
}

class Person
{
	private String name;
	private int age;
	Person(String name,int age)
	{
		//加入逻辑判断。
		if(age<0 || age>200)
		{
			throw new NoAgeException(age+",年龄数值非法");
		}
		this.name = name;
		this.age = age;
	}
	//定义Person对象对应的字符串表现形式。覆盖Object中的toString方法。
	public String toString()
	{
		return "Person[name="+name+",age="+age+"]";
	}
}

5、异常分类
(1)异常分为两类:
编译时异常:编译器会检测的异常。
运行时异常:编译器不会检测的异常。不需要声明。声明也可以,如果声明了,无外乎就是让调用者给出处理方式。
(2)常见异常
ArrayIndexOutOfBoundsException
IllegalArgumentException
NullPointerException
ClassCastException
RuntimeException 运行时异常
6、RuntimeExceptiom
(1)不是功能本身发生的异常,而是因为比如调用者传递参数错误而导致功能运行失败。
(2)运行时异常以及其子类都无需进行声明
(3)声明的目的是为了让调用者进行处理。不声明的目的是不让调用者进行处理,就是为了让程序停止,让调用者看到现象,并进行代码的修正。
7、异常的声明和捕获
声明:throws。将问题标识出来,报告给调用者
捕获:Java中对异常有针对性的语句进行捕获。
(1)捕获语句格式

try
{
	//需要被检测的语句。
}
catch(异常类 变量)//参数。
{
	//异常的处理语句。
}
finally
{
	//一定会被执行的语句。
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值