JAVA学习笔记(核心技术篇一)

目录

接口、继承与多态

类的高级特性

异常处理

Swing程序设计

集合类

I/O(输入/输出)


接口、继承与多态

类的继承
在JAVA中用extends关键字来标识两个类的继承关系
可以在子类中使用super关键字调用父类的构造方法或者父类的成员方法等,但子类没有权限调用父类中被修饰为private的方法。
重写(覆盖)就是在子类中将父类的成员方法的名称保留,重写成员方法的实现内容,更改成员方法的存储权限,或是修改成员方法的返回值类型。
如下代码中子类修改父类中dolt()方法的返回值类型,这类重写必须遵循一个原则,即重写的返回值类型必须是父类中同一方法返回值类型的子类
只修改实现内容的重写又被称作重构
当重写父类方法时,修改方法的修饰权限智能从小的范围到大的范围改变,即不能降低方法的修饰权限范围

class Test{
    public Test(){
        //some sentence
    }
    
    protected void doSomething(){
        //some sentence
    }

    protected Test dolt(){
        return new Test();
    }
}

class Test2 extends Test{    //继承父类
    public Test2(){          //构造方法
        super();             //调用父类构造方法
        super.doSomething(); //调用父类成员方法
    }

    protected void doSomethingNew(){    //新增方法
        //some sentence
    }

    protected void doSomething(){    //重写父类方法
        //some new sentence
    }

    protected Test2 dolt(){    //重写父类方法,方法返回值类型为Test2型
        return new Test2();
    }
}

在实例化子类对象时,父类无参构造方法将自动被调用,有参构造方法不能被自动调用,用户只能使用super关键字显式地调用父类的构造方法。
实例化子类对象之前需要先实例化父类对象,如下列代码及运行结果所示。
 

public class Parent {
	Parent(){
		System.out.println("调用Parent()构造方法");
	}
}

public class SubParent extends Parent {
	SubParent(){
		System.out.println("调用SubParent()构造方法");
	}
}

public class Subroutine extends SubParent {
	Subroutine(){
		System.out.println("调用Subroutine()构造方法");
	}

	public static void main(String[] args) {
		Subroutine s=new Subroutine();
	}
}

 

Object类
Object类是比较特殊的类,它是所有类的父类,是JAVA类层中的最高层类。由于所有类都是其子类,所以在定义类时可以省略extends Object关键字。
Object类中的getClass()、notify()、notifyAll()、wait()等方法不能被重写,因其被定义为final类型。
getClass()方法会返回对象执行时的Class实例,然后使用此实例调用getName()方法可以取得类的名称  getClass().getName()

对象类型的转换
向上转型:子类对象被看做是父类对象,即将具体类转换为抽象类
向下转型:将抽象类转换为具体的类,必须使用显示类型转换,以四边形为例,平行四边形是四边形,但四边形不一定是平行四边形,所以转换时必须指定这个四边形就是   平行四边形      父类类名  父类实例对象=(父类类名)子类实例对象

使用instanceof操作符判断对象类型
某类的对象引用 instanceof  某个类     该表达式的返回值为布尔值,若为true则表示某类的对象引用某个类的实例对象。

public class Parent {
	Parent(){
		System.out.println("调用Parent()构造方法");
	}
}
public class SubParent extends Parent {
	SubParent(){
		System.out.println("调用SubParent()构造方法");
	}
}
public class Subroutine extends SubParent {
	Subroutine(){
		System.out.println("调用Subroutine()构造方法");
	}

	public static void main(String[] args) {
		SubParent q=new SubParent();	//实例化父类对象1  
        //SubParent q=new Subroutine();	//实例化父类对象2
		//判断父类对象是否为Subroutine子类的一个实例
		if(q instanceof Subroutine) {
			System.out.println("父类对象q是Subroutine子类的一个实例");
			Subroutine p=(Subroutine) q;
		}
	}
}

 结果1             结果2

方法的重载
 方法的重载就是在同一个类中允许存在一个以上的同名方法,只要这些方法的参数个数、类型或者参数顺序不同即可。
定义不定长参数也可以作为重载的条件   返回值 方法名(参数数据类型...参数名称)   int add(int...a) 不定长参数可以看做是一个数组,(int...a)就相当于(int[ ] a)

多态
利用多态可以是程序具有良好的扩展性
将子类对象视为父类对象,可直接调用父类的方法

抽象类与接口
在解决实际问题时,一般将父类定义为抽象类,需要使用这个父类进行继承与多态处理。
JAVA中设置抽象类不可以实例化对象
abstract是定义抽象类的关键字
抽象方法没有具体方法体,这个方法本身没有任何意义,除非他被重写,而承载这个抽象方法的抽象类必须被继承,实际上抽象类除了被继承没有任何意义
只要类中有一个抽象方法,这个类就被标记为抽象类,抽象类在被继承后需要实现其中所以的抽象方法,也就是保证相同的方法名称、参数列表和相同的返回值类型创建出非抽象方法。
对于那些不需要使用抽象方法的子类来说,实现该抽象方法会造成代码冗余,此时可使用接口,详见下。

public abstract class Test{
    abstract void testAbstract();//定义抽象方法
}

接口是抽象类的延伸,可以将它看做是纯粹的抽象类,接口中所有的方法都没有方法体。可以将那些不是所有子类都需要的方法封装在接口中,使得需要该方法的子类实现这个接口。
接口使用interface关键字定义,具体定义语法如下:
 

public interface drawTest{
    void draw();    //接口内的方法,省略abstract关键字
}

在接口中,方法必须被定义为public 或abstract形式,不声明则默认是public;
在接口中定义的任何字段都自动是static和final的
 

public interface drawTest {	//定义接口
	public void draw();	//定义方法
}

public class SubParent1UseInterface extends ParentUseInterface implements drawTest{
	public void draw() {
		System.out.println("子类1.draw()");
	}
	public void doAnything() {
		System.out.println("子类1.doAnything()");
	}
}

public class SubParent2UseInterface extends ParentUseInterface implements drawTest{
	public void draw() {
		System.out.println("子类2.draw()");
	}
	public void doAnything() {
		System.out.println("子类2.doAnything()");
	}
}

public class ParentUseInterface {
	public void doAnything() {
		System.out.println("父类.doAnything()");
	}
	public static void main(String[] args) {
		drawTest[] d= {new SubParent1UseInterface(),new SubParent2UseInterface()};
        //接口也可以向上转型
		for(int i=0;i<d.length;i++) {
			d[i].draw();
            //d[i].doAnything(); 若添加该语句则报错,原因是drawTest接口中没有改方法,想成功运                            
            //行只能分开实例化子类对象,不能向上转型
		}
	}
}

在JAVA中不允许出现多重继承,但使用接口就可以实现多重继承,一个类可以同时实现多个接口,多重继承语法如下:
class 类名 implements 接口1,接口2,...,接口n
详见https://blog.csdn.net/Valentino112358/article/details/89036498?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161614310116780274174408%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161614310116780274174408&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-89036498.pc_search_result_before_js&utm_term=java%E6%8E%A5%E5%8F%A3%E7%BB%A7%E6%89%BF%E5%A4%9A%E4%B8%AA%E6%8E%A5%E5%8F%A3


类的高级特性

Java类包
包可以有效地管理繁杂的类文件,解决类重名的问题。要保证统一类包中的类不同名,JAVA中的每个类或者接口都来自不同的类包
以Math类为例,其全名是java.lang.Math  划线处是包的名称
在程序中使用两个不同Date类,可以参考如下代码:

java.util.Date date=new java.util.Date();
java.sql.Date date2=new java.sql.Date(233);

同一个包中的类相互访问时,可以不指定包名; 
同一个包中的类不必存放在同一个位置,只要CLASSPATH分别指向即可。

在类中定义包名的语法: package 包名 该表达式必须放在程序的第一行,必须是文件中的第一行非注释代码,指定包名后在使用该类时必须指定全名
包的命名规则:全部使用小写字母
使用 import 关键字导入包  如果为了导入包中更多的类,可以在包指定后加上*,这表示可以在程序中使用包中的所有类
使用 import 关键字导入静态成员:import static 静态成员

final变量
final关键字定义的变量必须在声明时对其进行赋值,一旦变量被定义就不可以再改变其值。除了修饰变量外,还可以用final修饰引用,一旦一个对象引用被修饰为final后,它只能恒定地指向一个对象,无法改变其指向另一个对象。一个既是static又是final的字段只占据一段不能改变的存储空间。

但是由于一个对象本身的值是可以改变的,因此为了使一个常量做到真正的不改变,可以将常量声明为 static final,代码如下
 

package com.lzw
import java.util.Random;
public class FinalStaticData {
	private static Random rand=new Random();
	private final int a1=rand.nextInt(10);
	private static final int a2=rand.nextInt(10);
	public static void main(String[] args) {
		FinalStaticData fdata=new FinalStaticData();
		System.out.println("重新实例化对象调用a1的值"+fdata.a1);
		System.out.println("重新实例化对象调用a2的值"+fdata.a2);
		FinalStaticData fdata2=new FinalStaticData();
		System.out.println("重新实例化对象调用a1的值"+fdata2.a1);
		System.out.println("重新实例化对象调用a2的值"+fdata2.a2);
	}
}


从本实例的运行情况可以看出,定义为final的常量不是恒定不变的。将随机数赋予定义为final的常量。可以做到每次运行程序时改变a1的值。但是a2与a1不同。由于他被声明为static final形式,所以在内存中为a2开辟了一个恒定不变的区域,刚再次实例化一个finalStaticData对象时,仍然指向a2这块区域,所以a2的值保持不变。a2在装载时被初始化,而不是每次创建新对象时都被初始化,a1会在重新实例化对象时被改变。

在JAVA中定义全局常量,通常使用public static final修饰,这样的常量只能在定义时被赋值。

可以将方法的参数定义为final类型,这样就不可以改变参数的值。

final方法
定义为final的方法不能被重写,若父类的某个方法被定义为private,因子类无法访问该方法,无法覆盖该方法,则无须再将该方法定义为final类型。
但是父类中定义的private final方法似乎能够被子类覆盖,代码如下:

public class Parent {
	private final void doit() {
		System.out.println("父类.doit()");
	}
	final void doit2() {
		System.out.println("父类.doit2()");
	}
	public void doit3() {
		System.out.println("父类.doit3()");		
	}	
}

public class SubParent extends Parent {
	public final void doit() {
		System.out.println("子类.doit()");
	}
	/*
	 * final void doit2() { System.out.println("子类.doit2()"); }
	 * 不能覆盖final方法
	 */
	public void doit3() {
		System.out.println("子类.doit3()");		
	}	
}

public class FinalMethod {
	public static void main(String[] args) {
		SubParent s=new SubParent();
		s.doit();
		Parent p=s;
		//p.doit(); 不能调用private方法
		p.doit2();
		p.doit3();
	}
}

从上述代码可以看出,final方法不能被子类覆盖,例如diot2()方法不能在子类中重写,但是父类中定义了private final方法doit(),从表面上看,子类中的doit()方法覆盖了父类中的doit()方法,但是覆盖必须满足一个对象向上转型为它的基本类型并调用相同方法这样一个条件,但是在主方法中向上转型时,对象p只能正常覆盖doit3()方法,却不能调用doit()方法,可见子类中的doit()方法并不是正常覆盖,而是生成了一个新的方法。

final类
定义为final的类不能被继承,语法为:final class 类名{ }
如果将某个类定义为final,则类中所有的方法都被隐式地设置为final类型,但是final类中的成员变量可以被定义为final或者非final形式。

内部类
内部类分为成员内部类、局部内部类、匿名类
1、成员内部类:在内部类中可以随意使用外部类中的成员方法以及变量,包括private类型,但内部类的成员不能被外部类使用。内部类的实例一定要绑定在外部类的实例上。
 

public class OuterClass {
	innerClass in=new innerClass();	//在外部类实例化内部类对象引用
	public void ouf() {
		in.inf();	//在外部类中调用内部类方法
	}
	
	class innerClass{
		innerClass(){	//内部类构造方法
		}
		public void inf() {
		}
		int y=0;
	}
	
	public innerClass doit() {	//外部类方法,返回值为内部类的引用
		//y=4;  报错,外部类不能直接访问内部类成员变量
		in.y=4;
		return new innerClass();	//返回内部类引用
	}
	public static void main(String[] args) {
		OuterClass out=new OuterClass();
		//内部类的对象实例化操作必须在外部类或外部类的非静态方法中实现
		OuterClass.innerClass in=out.doit();
		//在主方法中实例化内部类对象,必须在new操作符之前提供一个外部类的引用
		OuterClass.innerClass in2=out.new innerClass();
	}
}

内部类向上转型为接口
如果将一个权限修饰符为private内部类向上转型为其父类对象,或者直接向上转型为一个接口。在程序中就可以完全隐藏内部类的具体实现过程。可以在外部提供一个接口,在接口中声明一个方法。如果在实现该接口的内部类中实现该接口的方法,就可以定义多个内部类,以不同的方式实现接口中的同一个方法,而在一般的类中是不能多次实现接口中同一方法的。这种技巧经常被应用在swing编程中,可以在一个类中做出多个不同的响应事件。具体代码如下。

public interface OutInterface {
	public void f();
}

public class OuterClass2 {
	//定义一个内部类实现OutInterface接口
	private class InnerClass implements OutInterface{
		InnerClass(String s){
			System.out.println(s);
		}
		public void f() {
			System.out.println("访问内部类中的f()方法");
		}
	}
	public OutInterface doit() {
		return new InnerClass("访问内部类构造方法");
	}
}

public class InterfaceInner {
	public static void main(String[] args) {
		OuterClass2 out=new OuterClass2();
		//调用doit(
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值