Java2——封装

壹、类与对象

一、类的定义

  1. 类包括类声明和类体
    一个.java文件(一个编译单元),只能有一个public类,并且这个类名字要和.java名字相同。
public class ThisIsClass{//类声明
	//类体(包括属性和方法)
}

1. 属性的格式:访问权限 数据类型 属性名字

在这里插入图片描述
byte 8位,short 16位,int 32位,long 64位
float 32位,double 64位
char 16位
boolean 1位

//举个例子
public class Point2D{
	private float x;
	private float y;
}
public class Triangle{
	private Point2D pointOne;
	private Point2D pointTwo;
	private Point2D pointThree;
} 

2. 方法的格式:访问权限 返回类型 方法名(参数列表){方法体}

public class Triangle
{
	private float x;
	private float y;
	public float getX(){
		return x;
	}
	public float getY(){
		return y;
	}
	public void setX(float newX){
		x=newX;
	}
	public void setY(float newY){
		y=newY
	}
	
	public void setX0(float newX){//这个函数用在“三、”
		newX=50;
	}
}	

3. 构造方法:用来初始化类的私有属性

(1)每个类都有,如果没写,编译器就默认一个构造方法,没有参数,各私有属性均初始化成“0”这样的(数 0,字符 ‘\0’,布尔 false,对象 null)。但是如果自己写了构造方法,就没有这个构造方法了。
(2)默认访问权限public,名字为类名,无返回值(即不用写返回值)

public class Point2D{
	public float x;
	private float y;
	public Point2D(float setX,float setY){
		x=setX;
		y=setY;
	}
}

二、创建使用对象

	Point2D pointOne;//声明对象变量
	pointOne=new Point2D(114,514);//创建对象变量
	pointOne.x=1919810;//调用对象属性(x要是公共权限才行)
	System.out.println(pointOne.getX());//调用对象方法

1. 声明

Java中,对象变量名事实上代表一个地址,而不是直接指向这个内容。即pointOne是一个指针。不过一般就直接看做对象了。(注意,这个地址是对象所在内存空间的首地址
我们称呼这个对象名为引用。
所以,声明对象之后,pointOne的内容是一个32位地址,此时为null(Java的空是小写)

2. 创建

创建对象变量就是用new调用这个对象的构造函数,初始化这个对象。
new的作用有三点:
①引起对象调用构造方法
②为对象分配属性的内存空间
③返回一个该内存空间的首地址

3. 调用

通过.运算符调用对象属性及方法

//这种情况也能.运算符
int a = new Point(100,200).getX();

4. 使用完毕

对象的引用不存在时,该对象就变成了一个无用对象,Java的垃圾收集器会自动扫描对象的动态内存区,把没有引用的对象作为垃圾收集起来

三、参数传递

形参和实参(无论是基本数据类型还是对象)结合方式是值传递
意思就是说,
比如某个函数的参数是基本数据类型int b,那把参数a传到函数里,就是新建了一个基本数据类型b,在函数里可以任意修改b,但是a不受影响。
比如参数是对象B(是个地址),把对象A作为参数传到函数里,其实是新建一个引用(就是地址)指向A所指向的对象。
因此在函数里给B赋一个新值(new 对象),A不受影响。你我各拿两根线牵同一个毛球,你牵另一个毛球去了,和我还牵这个毛球有什么关系?
但是如果通过B用set修改对象里面的值,那A指向这个对象里面的值也就变了。你通过你那根线把毛球解散了,我牵的是同一个,不也散了吗?

//基本数据类型的值传递
	Point2D pointOne=new Point2D(100,200);
	float newX=300;
	pointOne.setX0(newX);
	System.out.println(newX);

按理说,setX0函数中修改了newX的值成50,打印出来就应该是50,但是事实上打印出来是300。
原因就在值传递就是把newX穿进去,在newX中新建了一个变量newX,修改这个newX和原来那个newX没有关系

//对象的值传递
public void changePoint1(Point2D pointOne){
	pointOne=new Point2D(300,400);
}
public void changePoint2(Point2D pointOne){
	pointOne.x=300;
	pointOne.y=400;
}
Point2D pointOne=new Point2D(100,200);
changePoint1(pointOne);
System.out.println(pointOne.get());
changePoint2(pointOne);
System.out.println(pointOne.get());

分别打印出100,300
为什么呢?
函数的形式参数是pointOne,这是个地址。所以函数changePoint1相当于为这个地址变量赋了一个新值。所以原来那个pointOne没有受到影响。函数changePoint2则是修改这个地址指向的对象的属性,直接修改,所以修改成功。

总之,只要把握对象变量名是一个地址就能理解

四、方法重载

如果有几个函数,名字不得不取得相同,但是参数类型或参数数量不同,那就可以写几个函数名一样的函数,调用的时候编译器根据参数列表决定到底调用哪个。
注意,参数不一样才算重载(顺序不一样也行)。参数数目和对应类型一样,返回类型不一样可不行,编译器怎么区分你要调用哪个?

public class Point{
	private float x;
	private float y;
	private float z;
	public Point(){
		x=0;
		y=0;
		z=0;
	}
	public Point(float newX){
		x=newX;
		y=0;
		z=0;
	}
	public Point(float newX,String T){
		this(newX);//是Point(newX);的意思
		System.out.println(T);//输出提示字符串
	}
}

就像上面,我可以调用Point(),也可以调用Point(100),就会起到不同效果

错误示例:

//错误示例1,接上
public Point(float newX){
	x=newX;
}
public Point(float newY){
	y=newY;
}
public Point(float newZ){
	z=newZ;
}

这个例子错误就在参数数量和类型一样,导致调用时编译器分不出来该调用哪个,编译器认为这是“方法的重定义”而报错

//错误示例2,接上
public void printOut(String T){
	System.out.println(T);
}
public String printOut(String T){
	System.out.print(T);
	return 'y';
}

这个例子错在返回类型不同不算重载

五、static和main()

1.static

(1)称呼

不知道怎么回事,这些称呼有一大堆,发明这些称呼的人真是闲得无聊。干脆一大堆同义词指定只有一个标准的,谁用不标准的就扣工资,不就不混乱了吗?
不加static的变量称为 实例变量 或 对象变量
加了的变量称为 类变量 或 静态变量 或 类属性 或 静态属性
不加static的方法称为类的 实例方法 或 对象方法
加了的方法称为 类方法 或 静态方法

(2)变量

①通常,同一个类,不同对象里面的变量是相互 独立的,修改你的x不会影响我的x。但是加了static,那类创建的所有对象,就共用这同一个变量。有一点点像全局变量。
可以说,加了static,那这个变量就是这个类的变量,属于大家每个对象。

public class point{
	private float x;
	private static float y=0;
}

就比如上述情况,如果创建了3个变量,那就有3个相互独立的x,然而y只有一个,一旦修改,那对于所有对象相当于都修改了
②访问:
正确访问方式:类名.类变量
错误访问方式:this.类变量,在这个this所指的对象内存空间里,是找不到类变量的
③有什么用呢:

public class Point{
	private float x;
	private float y;
	private static int pointNum=0;
	public Point(float newX,float newY){
		x=newX;
		y=newY;
		pointNum++;
	}
}

上述可以统计总共建立了多少个点

(3)方法

①实例方法:不加static的
事实上,一个类的实例方法在内存中只有一份拷贝,但是,

Point1.setX(100);
Point2.setX(200);

既然只有一份拷贝,那两个对象都要调用,方法怎么知道改变哪个对象的X呢,注意,方法只看参数列表,前面.运算符和调用它的对象并不是参数。
为什么呢?原因就是编译器会自动把上面翻译成下面:

Point1.setX(100);
Point1.setX(Point1,100);

函数整体则变成

public void setX(Point2D this,float newX){
	this.x=newX;
}

②类方法
只能访问类变量,不能访问实例变量
只能调用类方法,不能调用实例方法(实例方法倒是可以调用类方法)
由类名和对象名均可调用
没有上述实例方法的this变量,不事先声明,this就相当于没用(因为是整个类的方法,对某个具体对象没用)

2. main()

(1)格式

用语言说,就是:main()是公开的静态方法,返回类型是void,形参位String数组
用代码写,就是public static void main(String[] args){}

(2)一些说明

①任何类都可以有一个静态的main()方法,可以编写测试这个类的代码。开始运行前,可以选择从哪个类的main()开始运行。
②main()是静态方法,不能直接访问实例变量,调用实例方法,所以需要先建立一个对象,通过对象访问实例变量,调用实例方法。也就是说,在main方法里新建对象之后才能用对象的实例变量、实例方法

//写个完整的
public class Point2D{
	private float x;
	private float y;
	private static int pointNum=0;
	public Point2D(float setX,float setY){
		x=setX;
		y=setY;
		pointNum++;
	}
	public float getX(){
		return x;
	}
	public float getY(){
		return y;
	}
	public void setX(float newX){
		x=newX;
	}
	public void setY(float newY){
		y=newY;
	}
	public static int getPointNum(){
		//x=100;注意这句是错的,不能访问实例变量
		return pointNum;//用静态方法调用静态变量
	}
	public static void main(String[] args){
		setX(100.0);//错误,静态方法不能调用实例方法
		System.out.println(getPointNum());//正确
	}
}	

六、final

作用就在于防止修改。一个public final变量可以当成常量使用,不同担心被修改,也必须写成全大写,就比如public static PI = 3.14
写在所有的前面,使用final的变量必须一开始就初始化一个值,除非在所有的构造函数中都有初始化值。

//可能语法不正确,毕竟刚学Java......
final int x;
final int getX(){
	return x;
}
final class X{
}

1.修饰成员变量

(1)结果:修饰之后值不能被修改,在声明成员变量时需要给出初始值(或者在所有的构造函数中都要初始化这个变量)。修饰局部变量时可以不用给初始值

//正确1
public class FinalResult(
	final int score=60;
	public FinalResult(){
	}
}
//正确2
public class FinalResult{
	final int score;
	public FinalResult(){
		score=60;
	}
}
//错误1
public class FinalResult{
	final int score=60;
	public FinalResult(){
		score=100;//初始化之后不能再修改
	}
}
//错误2
public class FinalResult{
	final int score;
	public FinalResult(){
		//没有直接初始化,构造函数中也没有
	}
}

2. 修饰成员方法

可以被子类继承,但是子类不能覆写它

3. 修饰类

不能被继承,也就是不能有子类 (原因:继承,就意味着子类要从ful)

七、编译单元

  1. 编译单元:一个.java命名的源文件
  2. 每个编译单元包含若干个类,每个类都可以有main(),使之可以单独运行
  3. 但每个编译单元仅允许至多一个类是public,且编译单元的名字要和这个public类一样

贰、访问权限

一、包

1. 说明

作用:组织、管理类,解决类名冲突的问题
大概定义:存储一个及以上功能相关的类

2. API:Java应用程序接口,就是类库

例如:java.io,输入输出包
           java.net,网络包

3. 导入

Java.util.Data.data=new Java.util.Data();//用类的全名引用类
import java.util.*;//import导入包
import java.util.Data;//import导入类

PS1:同一个包内的类可以相互引用,不用全名或import
PS2:java.lang不用import

4. 自定义包

package shape;//必须是文件中第一条语句(除了空格和注释不能有其他东西)
class Point2D{
	float x;
	float y;
}
class Triangle{
	Point2D pointOne;
	Point2D pointTwo;
	Point2D pointThree;
}
//使用例一
public class EqualTriangle{//全名法
	shape.Triangle triangleOne;
	shape.Triangle triangleTwo;
}
//使用例二
import shape.*;//导入法
public class EqualTriangle{
	shape.Triangle triangleOne;
	shape.Triangle triangleTwo;
}

二、类的访问权限

1. 类只有两种访问权限

public和缺省(其实就是默认的意思,实际操作是class前不加单词。吐槽一句,缺省这个词真是莫名其妙,不明所以)

2.说明

public:只要被导入或使用名字,就可以被所有包中的所有类使用(不同的包之间的类默认不相互可见)
缺省:包访问性,只能被同一个包的类访问引用

package a;
class First{
	int num=1;
}
public class Second{
	int number=1;
}
import a;
public class NO1{
	First newclass1;//不行,不能使用其他包的缺省类
	Second newclass2;//可以,Second是public权限
}

三、成员的访问权限

1.private,私有

只能被这个类自己内部 使用
如果其他类想要访问,需要使用这个类提供的get,set之类的方法

2.public,公共

另一个包import之后,另一个包内可以任意使用这个属性

3.protected,保护

可以被同类、同包、不同包子类 使用

4. 啥都不写,默认(缺省)(default)

可被同包的类访问

private<默认<protected<public

叁、Java类库举例

一、Java.lang.String

1.Java的字符串从索引0到索引n-1
2.常见函数

	str1.equals(str2);//比较两个字符串,返回boolean*
	System.out.println(str1.length());//字符串长度,每个字符(16位)长1,
	System.out.println(str1.charAt(666));//返回第666个字符
	str1.toLowerCase();//全转小写
	str1.toUpperCase();//全转大写
	str1.substring(4,8);//返回索引4到索引8这一个子串
	str1.concat(str2);//把str2接到str1后面
	str1.indexOf(str2);//查找str1中有没有str2子串,如果有就返回其索引

PS:如果用str1==str2比较两个字符串,结果一般都是false,因为str1,str2是类名,除了某些特殊情况,比较它俩一般都是比较地址
3. 其他
(1)将数值数据转换成字符串

//一,+
System.out.println("You scored "+60);//尽管60不是字符串,还是输出了You scored 60,因为60转换成字符串了。一堆数据out,一个是字符串,输出的就是全员转化为字符串
//二,toString
String strValues;
strValues=String.valueOf(5.87);//"5.87"
strValues=String.valueOf(true);//"true
//三,Integer
String strValues;
strValues=Integer.toString(18);

(2)连接字符串:str1 = str1.concat(str2)也可以,str1 += str2也可以。
不过注意,str1.concat(str2)整体是一个字符串,只写str1.concat(str2);不管用,要写str1 = str1.concat(str2);
另外,字符串+对象名,就相当于原字符串+这个对象.toString()
(3)字符串转化为数值
下列两种方法都行。不过第一种事实上返回的是Double对象

double i = Double.valueOf("1.048596");
double j = Double.parseDouble("1.048596");

二、StringTokenizer

  1. 作用:字符串解析
  2. 导入:
import java.util.StringTokenizer
  1. 构造函数
StringTokenizer(str);//默认分隔符来分割
StringTokenizer(str,delim);//用delim作为分割符
StringTokenizer(str,delim,judge);//如果judge值为true,那切分结果包括分隔符

默认分割符:空格、制表、换行、回车
4. 常用函数

str=nextToken();//返回当前的下一个切分单元
num=countTokens();//当前往后还可以用几次nextToken
judge=hasMoreTokens();//是否可以继续切分
  1. 举个例子
    格式:name-quantity-price-total,切分
public static Product CreateProduct(String str,String delim){
	StringTokenizer tokenizer=new StringTokenizer(str,delim);
	if(tokenizer.countTokens()==3){
		String name=tokenizer.nextToken();
		int quantity=Integer.parseInt(tokenizer.nextToken());
		double price=Integer.parseDouble(tokenizer.nextToken()):
	}else{
		return null;
	}
}

*注意,Integer就是上面的类型转换,parseInt就是把后面那个字符串转换成int型,parseDouble同理

三、标准IO

  1. I
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))

String  input = stdIn.readLine(); 
  1. O
//标准输出
PrintWriter  stdOut =  new PrintWriter(System.out, true);
stdOut.println(“the result is :"); 
//错误输出
PrintWriter  stdErr =new PrintWriter(System.err, true);
stdErr.println(“Incorrect number format");

肆、异常处理机制

一、意义

  1. 异常:可恢复的Java运行时错误
    在编写C程序时,经常发现不能直接写到底,经常要考虑如果用户输入了奇奇怪怪的东西怎么办,然后就要写一堆if else,然后debug又看得头晕。java为了避免这种情况,引入了异常处理机制,把异常放到后面一块处理
  2. 异常类:异常事实上有两种,Error和Exception,Error发生,只能等待程序崩溃,Exception则是可以处理控制的。
    Java这么喜欢类,异常当然也要弄成类。

(1)两种异常分别定义成异常类,共同有一个父类Throwable。Throwble有三个方法:
①getMessage() :返回此throwable的详细信息(String类型)
②printStackTrace():将此throwable及其追踪输出至标准错误流(void)
③toString():返回此throwable的简短描述
(2)Exception还分为两类,checked exception,unchecked exception
非检测异常:所有以RuntimeException为基类的,就是运行时异常罢了。可以不处理,处理了可以增加程序健壮性
检测异常:除此以外的Exception类
(3)示例:稍微看一看就好,看完这一节再回头看这块代码

public class ExceptionMethods{
	public static void main(String[] args){
		try{
			g();
			System.out.println("异常没抛出去就会打印这一行");
		}catch(Exception e){
			System.out.println("这里有Exception");
			System.out.println("e.getMessage()内容:"+e.getMessage());
			System.out.println("e.toString()内容:"+e.toString());
			System.out.println("e.printStackTrace()内容:");
			e.printStackTrace();
		}
	}	
	public static void g()throws Exception{
		f();
		System.out.println("异常没抛出去就会打印这一行");
	}
	public static void f() throws Exception{
		throw new Exception("测试一下异常");
	}	
}

二、throw关键字

  1. 格式:throw加一个异常对象。
    目的:为了说明某处出现错误,需要处理
  2. 示例
public IfPositive(int number)throws OutofRangeException{
	if(number<0){
		throw new OutOfRangeException("Number not positive");
	}else{
		this.value=number;	
	}
}

如果参数小于零,就抛出OutOfRangeException异常,否则把number赋值给value

三、try-catch

try{
	//正常逻辑
}catch(Type1 id1){
	//处理Type1类型的异常
}catch(Type2 id2){
	//处理Type2类型的异常
}

如果没有异常,那执行完try直接跳到最后一个catch后面
如果有异常:try中止,逐个检查catch,
①直到找到(也就是说如果有多个catch符合,只执行第一个):执行这个catch的内容
②最后也没找到:如果有写finally,就执行finally里面的,如果没有,将异常抛出给调用它的方法,让它try-catch
*可以把finally类比成switch-case里面的default
③上述一路抛出,直到主函数也没找到对应catch:运行中止,Java程序退出,在命令行窗口报告抛出的异常信息

//具体举个例子
import java.util.Scanner;
public class trycatch {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);//现在只要知道这一行用来输入就可以了
        String name=""; 
        int age=0; 
        try {
            System.out.print("输入学生姓名:");
            name=scanner.next();
            System.out.print("输入学生年龄:");
            age=scanner.nextInt();
        } catch (Exception e) {
            System.out.println("输入有误!");
        }
        System.out.println("姓名:" + name);
        System.out.println("年龄:" + age);
    }
}

四、throws

  1. 情况:可能有一个检测异常,但是方法体内没有处理部分,则必须通过throws抛出去
  2. 使用
    throw,写的时候说明确定地知道这时候就要抛出异常了
    throws,说明接下来的代码有几种异常可能,遇到其中一种就抛出
//转载别人的一段代码
void doA(int a) throws IOException,{//注意throws后面可跟几种异常可能
           try{
                 ......

           }catch(Exception1 e){
              throw e;
           }catch(Exception2 e){
              System.out.println("出错了!");
           }
           if(a!=b)
              throw new  Exception3("自定义异常");
}

原博主的说明:
代码块中可能会产生3个异常,(Exception1,Exception2,Exception3)。
如果产生Exception1异常,则捕获之后再抛出,由该方法的调用者去处理。
如果产生Exception2异常,则该方法自己处理了(即System.out.println(“出错了!”);)。所以该方法就不会再向外抛出Exception2异常了,void doA() throws Exception1,Exception3 里面的Exception2也就不用写了。
而Exception3异常是该方法的某段逻辑出错,程序员自己做了处理,在该段逻辑错误的情况下抛出异常Exception3,则该方法的调用者也要处理此异常。

五、自定义异常

就是抛出异常的名字自己写,不依赖编译器提供。然后抛出的异常,由于是自己写的,所以含义也看得懂,适合特定业务情况

举个例子,银行业务要求输入字符串满足如下格式:
姓名—年龄—账号

import java.util.*;
import java.io;

public class Employee{
	private String name;
	private int age;
	private String account;
	private static PrintWriter strOut=new PrintWriter(System.out,true);
	private static BufferedReader stdIn=new BufferedReader(new InputStreamReader(System.in));

	public static void main(String[] args)throws IOException{
		Employee employee=null;
		while(employee==null){
			try{
				stdOut.println("请输入雇员的基本信息");
				employee=new Employee(stdIn.readLine());
				//构造方法中声明了两种可能的自定义异常,如果都没有,就继续下面的输出
				System.out.println(employee);
			}catch(LackOfStringUnionException losue){//losue就是首字母合在一起,下面nfe一样
				System.out.println("参数个数太少");
			}catch(NumberFormatException nfe){
				nfe.printStackTrace();
				System.out.println("年龄无效");
			}
		}	
	}
	public Employee(String data)throws LackOfStringUnionException,NumberFormatException{
		StringTokenizer a=new StringTokenizer(data,"——");
		String validator;
		
		//参数个数
		if(a.countTokens()!=5){//这就抛出了一个自定义异常
			throw new LackOfStringUnionException;
		}
		for(int i;a.hasMoreElements();i++){
			switch(i){
				case 0:
					name=a.nextToken();
					break;
				case 1:
					age=Integer.valueOf(a.nextToken());
					break;
				case 2;
					account=a.nextToken();
					break;
				default:
					break;
			}
		}	
	}
	public class LackOfStringException extends Exception{
		//重点到了,前面抛出了异常,事实上这里要自己写一段处理代码.下面是借助了Exception这个父类来处理
		public LackOfStringUnionException(){
			super();
		}
		public LackOfStringUnionException(String message){
			super(message);
		}
	}		
}

伍、编写Javadoc

为了让使用这个类的人一看说明就知道这个类怎么用,不用研究源代码。在代码里写Javadoc,编译器会自动解析Javadoc并生成一个html网页,别人一看就懂

一、编写规范

  1. Java有两种注释方式,都和C一样。但是/**/这种扩展一下就作为Javadoc格式
//单行模式
/** 内容 */

//多行模式
/**
*内容
*内容
*/
  1. Javadoc标签:以@开头的。不仅注释源代码,更可以作为解析源文件的依据

二、标签

  1. 格式
/**
*@标签名 标签参数 注释体
*/

标签名:描述了注释体应该有的内容,制定了Javadoc命令解析此条注释的方法
标签参数:可选,为标签提供额外参数
注释体:可选,可以是 注释的主体部分 或 对标签的说明

  1. 不同标签的作用范围:
    ①作用于类:用于声明版本、作者、日期,需要写在一个类的开头
    ②作用于方法:描述某个方法的详细信息,比如参数,返回值之类的
  2. 常用标签
    在这里插入图片描述
    补充一下,还有@throws标签,和@exception差不多,可以混用
import java.io.IOException
/**
*这句话将出现在生成的Javadoc中类的说明部分。
*@author DonaldTrump DonaldTrump@gmail.com
*@author JoeBiden JoeBiden@gmail.com
*@version 1.0.0
*/ 
public class Test{
	/**	
	  *这句话将出现在生成的Javadoc中字段摘要部分
	  */
	private int number;
	/**
	  *这句话将出现在生成的Javadoc中方法摘要部分
	  *该方法为number设置一个新的值
	  *@param newNumber 给number新的数值
	  *@return 原来的数值
	  *@exception IOException 如果传入的新值为负则抛出IOException
	  */
	  public int setNumber(int newNumber){
	  	if(newNumber<0){
	  		throw new IOException;
	  	}else{
	  		int result=number;
	  		number=new Number;
	  		return result;
	  	}
	  }
}	  
...
/**
*创建一个到 指定类 的链接
*@see org.ssd3.Test
*创建一个到 指定变量 的链接
*@see number
*创建一个到 指定方法 的链接
*@see org.ssd3.Test#test
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值