Java认识对象

①友好变量、友好方法、友好类
不用private、public、protected修饰符修饰的成员变量和方法被称为友好变量和友好方法。
例:当在另一个类中用类Tom创建了一个对象后,如果这个类与Tom类在同一个包中,那么该对象能访问自己的友好变量和友好方法。
②实例变量与类变量
声明
class A{
float x;//实例变量
static int y;//类变量
}
区别:1.不同对象的实例变量互不相同
2.所有对象共享类变量
3.通过类名直接访问类变量
③实例方法与类方法
声明

class A{
	int a;
	float max(float x,float y){....}//实例方法
	static float jerry(){....}//类方法
}

区别:1.对象调用实例方法
2.类名调用类方法
注意:若一个类中要使用友好类创建对象,亚保证他们在同一个包中。
1.不能用protected和private修饰类
2.访问限制修饰符按访问权限从高到低的排列顺序是public、
protected、友好的、private
④数据特点
栈特点:
1.栈描述的方法执行的内存模型,每个方法都被调用都会创建一个栈帧 (存储局部变量、操作数、方法出口等)
2.JVM为每个线程创建一个栈、用于存放该线程执行方法的信息(实际参数、局部变量等)
3.栈属于线程所有,不能实现线程间的共享
4.栈的存储特性是“先进后出,后进先出”
5.栈是由系统自动分配,速度快!栈是一个连续的存储空间

堆特点:
1.堆用于存储创建好的对象和数组(数组也是对象)
2.JVM只有一个堆,被所有线程共享
3.堆是一个不连续的内存空间,分配灵活,速度慢

方法区(静态区)特点:
1.JVM只有一个方法区,被所有线程共享
2.方法区实际也有堆,只适用于存储类、常量相关信息
3.用来存放程序中永远是不变或唯一的内容

⑤使用标准类
1.使用java.util.Scanner
import java.util.Scanner;//可以不用每次都输入java.util.Scanner
Scanner对每个基本类型,都会有对应的nextxxx()方法,
如nextByte(),nextShort(),nextLong(),nextFloat(),nextDouble(),nextBoolean()等,
如果直接取得上一个字符串(以空格或换行分割),则用next(),如果想取得用户输入的整行文字,则使用nextLine()

2.使用java.math.BigDecimal
由于浮点数的运算是不精确的,如果要求精确度,那就要小心使用浮点数,
而且别用==直接比较浮点数运算结果
import java.math.BigDecimal;
在类里写

 BigDecimal operand1=new BigDecimal("1.0");
    		BigDecimal operand2=new BigDecimal("0.8");
    		BigDecimal result=operand1.subtract(operand2);
    		//相减,BigDecimal提供有plus()、substract()、multiply()、
    		//divide()等方法,可以进行加减乘除等运算

此时得到的结果是精确的。

3.对象指定与相等性
在上一范例中,比较两个BigDecimal是否相等,是使用equals()方法而非使用==运算。原因如下:

如果你在操作对象,=是用在指定参考名称参考某个对象,而==是用在比较两个参考名称是否参考同一对象。

例:

BigDeciaml a=new BigDecimal("0.1");
BigDeciaml b=new BigDeciaml("0.1");
System.out.println(a==b);//显示false
System.out.println(a.equal(b));//显示true

⑥基本类型打包器
1.打包基本类型
可以使用Long、Integer、Double、Float、Boolean、Byte等类来打包基本类型,正如此名称所示,这些类主要目的就是提供对象实例作为“壳”,将基本类型打包在对象之中,这样就可以操作这些对象,就像是基本类型当做对象操作。
例:

int data1=10;
int data2=20;
Integer wrapper1=new Integer(data1);//打包基本类型
Integer wrapper2=new Integer(data2);
System.out.println(data1/3);//基本类型运算 输出3
System.out.println(wrapper1.doubleValue()/3);
//操作打包器方法 输出3.33333333
System.out.println(wrapper1.compareTo(wrapper2));

基本类型打包器都是归于java.lang包中,如果要使用Integer打包int类型数据,方法之一是使用new创建Integer实例时,传入int型数据。因为如果表达式中都是int,就只会在int控件中做运算,结果会是int整数,因此data1/3就会显示3的结果,也可以操作Integer的doubleValue()将打包值以都变了类型返回,这样就会在double空间中做相除,结果就是3.333333…
Integer提供compareTo()方法,可与另一个Integer对象进行比较,如果打包值相同就返回0,小于compareTo()传入对象打包值就返回-1.否则就是1.

2.自动装箱、拆箱
除了使用new创建基本类型打包器之外,可以这样打包基本类型:
Integer wrapper=10;
编译程序会自动判断是否能进行自动装箱,用自动装箱改写一下上面的代码

Integer data1=10;
Integer data2=20;
System.out.println(data1.doubleValue()/3);
System.out.println(data1.compareTo(data2));

程序看来简洁很多
还可以按如下形式写

int i=10;
Integer wrapper=i;

也可以使用更一般化的Number类来自动装箱。例如:

Number number=3.14f;

3.14f会先被自动装箱为Float,然后指定给number。

可以自动装箱,也可以自动拆箱。
例如:

Integer wrapper=10;//自动装箱
Integer foo=wrapper;//自动拆箱

wrapper会参考至Integer,若被指定给int型的变量foo,则会自动取得打包的int类型再指定给foo

运算时,也可以进行自动装箱与拆箱
例如:

Integer i=10;
System.out.println(i+10);
System.out.println(i++);

上例中会显示20,10,编译程序会自动装箱与自动拆箱,也就是10会先装箱,然后在i+10时会先对i拆箱,再进行加法运算,i++该行也是先对i拆箱再进行递增运算。
3.自动装箱、拆箱内幕
使用Integer.valueOf()也是为基本类型建立打包器的方式之一

Integer i=null;
int j=i;

但执行时会有错误,因为编译程序会将之展开为:

Object localObject=null;
int i=localObject.inValue();

在Java程序代码中,null代表一个特殊对象,任何类声明的参考名称都可以参考至null,表示该名称没有参考任何对象实体。
但是,有一些隐藏的细节需要注意,例如:

Integer i1=100;
Integer i2=100;
if(i1=i2){
	System.out.println("i1==i2");
}
else{
	System.out.println("i1!=i2");
}//输出i1==i2

如果将100换为200,则情况不同

Integer i1=200;
Integer i2=200;
if(i1=i2){
	System.out.println("i1==i2");
}
else{
	System.out.println("i1!=i2");
}//输出i1!=i2

原因是valueOf()的操作内容:

public static Integer valueOf(int i){
	if(i>=IntegerCache.low && i<=IntegerCache.high)
		return IntegerCache.cache[i+(-IntegerCache.low)];
}

//其中IntegerCache.low默认值为-128,IntegerCache.high默认值是127
//所以出现了上面的情况,如果想要修改默认值,可以
//在启动JVM时,使用系统属性java.lang.IntegerCache.high来指定。例如:
//java -Djava.lang.IntegerCache.high=300 cc.openhome.Demo
//cc.openhome.Demo是文件名

⑦数组对象
1.如果要存储10个变量

int score1=88;
//...
int score10=93;

实际上不可能这么做,用数组处理即可

int[] scores={88,81,74,68,78,76,77,85,95,93};

如果想一次取出每一个值,方法之一是使用for循环

int[] scores={88,81,74,68,78,76,77,85,95,93};
for(int i=0;i<scores.length;i++){
	System.out.printf("学生分数:%d %n",scores[i]);
}

也可以写成:

for(int score:scores){
	System.out.printf("学生分数:%d %n",score);
}

2.二维数组

int[][] cords={
	{1,2,3},
	{4,5,6}
};  //声明二维数组并赋予初始值
for(int x=0;x<cords.length;x++){ //得知有几列
	for(int y=0;y<cords[x].length;y++){ //取得每列的长度
		System.out.printf("%2d",cords[x][y]);  //指定列、行索引取得数组元素
	}
	System.out.println();
}

用增强式for语句写起来比较简练:

for(int[] row:cords){
	for(int value:row){
		System.out.printf("%2d",value);
	}
	System.out.println();
}

3.操作数组对象
用new关键字建立数组:

int[] scores=new int[10];

int类型定义的数组,初始化默认是0
String类型定义的数组,默认值是null
char类型定义的数组,默认值是0对应的字符
double类型定义的数组,默认值是0.0
float类型定义的数组,默认值是0.0

如果默认初始值不符合要求,可以使用java.util.Arrays的fill()方法来设定新建数组的元素值。
例如:将每个学生的成绩默认为60分起:

import java.util.Arrays;//引入方法
int[] scores=new int[10];
for(int score:scores){
	System.out.printf("%2d",score);//输出0 0 0 0 0 0 0 0 0 0
}
System.out.println();
Arrays.fill(scores,60);
for(int score:scores){
	System.out.printf("%3d",score);//输出60 60 60 60 60 60 60 60 60 60
}

如果想在new数组中一并指定初始值,可以这样写,注意不必指定数组长度:

int[] scores=new int[]{88,81,74,68,78,76,77,85,95,93};

看看如下例子:

int[] score1={88,81,74,68,78,76,77,85,95,93};
int[] score2=score1;
score2[0]=99;
System.out.println(score1[0]);//输出99

因为数组是对象,而score1与score2是参考名称,将score1指定给score2,意思就是将score1参考的对象也给score2参考

如果想用new建立二维数组,也可以如下:

int[][] cords=new int[2][3];

没有人规定二维数组一定得是矩阵,也可以建立不规则的数组,例如:

int[][] arr=new int[2][];//声明arr参考的对象会有两个索引
arr[0]=new int[]{1,2,3,4,5};//arr[0]是长度为5的一维数组
arr[1]=new int[]{1,2,3};//arr[1]是长度为3的一维数组

所以,这么建立数组也是可以的:

int[][] arr={
	{1,2,3,4,5},
	{1,2,3}
};

关于为什么int的默认值为0,而Integer的默认值为null:
Java为每个原始类型提供了封装类,Integer是java为int提供的封装类。
int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况

4.数组复制
了解完数组是对象,我们就应该知道,以下这个并非数组复制:

int[] scores1={88,81,74,68,78,76,77,85,95,93};
int[] scores2=scores1;

这个程序段不过是将scores1参考的数组对象,也是给scores2参考,如果真的要数组复制,基本做法是另行建立数组。
例如:

int[] scores1={88,81,74,68,78,76,77,85,95,93};
int[] scores2=new int[scores1.length];
for(int 1=0;i<scores1.length;i++){
	scores2[i]=scores1[i];
}

事实上,可以使用System.arraycopy()方法,这个方法会使用原生方式复制每个索引元素,比自行使用循环来得快

int[] scores1={88,81,74,68,78,76,77,85,95,93};
int[] scores2=new int[scores1.length];
System.arraycopy(scores1,0,scores2,0,score1.length);
//System.arraycopy()的五个参数分别是来源数组、来源起始索引、目的数组、目的起始索引、复制长度

JDK6以上,还可以使用更方便的Arrays.copyOf()方法,你不用另行建立新数组,Arrays.copyOf()会帮我们建立
例如:

import java.util.Arrays;
int[] scores1={88,81,74,68,78,76,77,85,95,93};
int[] scores2=Arrays.copyOf(score1,score1.length);
//copyOf(复制数组名,长度)
//如果修改score2的内容,不影响score1

以上都是基本类型数组,对于类类型声明的数组则要注意参考的行为。
例:

class Clothes{
	String color;
	char size;
	Clothes(String color,char size){
		this.color=clor;
		this.size=size;
	}
}
public class ShallowCopy{
	public static void main(String[] args){
		Clothes[] c1={new Clothes("red","L"),new Clothes("blue","M")};
		Clothes[] c2=new Clothes[c1.length];//浅层复制
		for(int i=0;i<c1.length;i++){
			c2[i]=c1[i];
		}
		c1[0].color="yellow";//通过c1修改索引0对象
		System.out.println(c2[0].color);//通过c2取得索引0对象的颜色  输出yellow
	}
}

实际上循环中仅将c1每个索引处所参考的对象,也给c2每个索引来参考,并没有实际复制出Clothes对象,术语上来讲,这叫做复制参考,或者称这个行为是浅层复制,无论System.arraycopy()还是Array.copyOf(),用在类类型声明的数组时,都是执行浅层复制。

如果真想要连同对象一同复制,我们需要自行操作,因为基本上只有自己才知道每个对象复制时,有哪些属性必须复制,例如:

class Clothes2{
    	String color;
    	char size;
    	Clothes(String color,char size){
    		this.color=clor;
    		this.size=size;
    	}
    }
public class DeepCopy{
	public static void main(String[] args){
		Clothes2[] c1={new Clothes("red","L"),new Clothes("blue","M")};
    		Clothes[] c2=new Clothes[c1.length];
		for(int i=0;i<c1.length;i++){
			Clothes2 c=new Clothes2(c1[i].color,c1[i].size);
			c2[i]=c;
		}
		c1[0].color="yellow";
		System.out.println(c2[0].color);//输出red
	}
}

5.字符串对象
字符串基础

.length()//取得字符串长度
.charAt()//指定取得字符串中某个字符,索引从0开始
.toUpperCase()//将原本小写的字符串内容转为大写的字符串内容
static byte parseByte(String str)//:将字符串参数解析为一个有符号的十进制byte
static short parseShort(String str)//:将字符串参数解析为一个有符号的十进制short
static int parseInt(String str)//:将字符串参数解析为一个有符号的十进制int
static long parseLong(String str)//:将字符串解析为一个有符号的十进制long
static float parseFloat(String str)//:将字符串参数解析为float值
static double parseDouble(String str)//:将字符串参数解析为double值
static boolean parseBoolean(String str)//:将字符串参数解析为boolean值

例:

long number=0;
number=Long.parseLong("1");//此时number=1

字符串特性
看看下面的程序片段,是返回true还是false

char[] name=('J','u','s','t','i','n');
String name1=new String(name);
String name2=new String(name);
System.out.println(name1==name2);//false

由于name1,name2分别参考至创建出来的String对象
那么下面的代码呢?

String name1="justin";
String name2="justin";
System.out.println(name1==name2);//true

由于name1与name2参考同一个对象,Java为了效率考虑,以""包括的字符串,只要内容相同(序列、大小写相同),无论在程序代码中出现几次,JVM都只会建立一个String实例,并在字符串池中维护。
那么下面的代码呢?

String name1="justin";
String name2="justin";
String name3=new String("justin");
String name4=new String("justin");
System.out.println(name1==name2);//true
System.out.println(name1==name3);//false
System.out.println(name3==name4);//false

因为justin会建立String实例并在字符串池中维护,所以name1与name2参考的是同一个独享,而new一定是建立新的对象,所以name3与name4分别参考至新建的String实例。

如果想比较字符串实际字符内容是否相同,不要使用==,要使用equals()。

    String name1="justin";
    String name2="justin";
    String name3=new String("justin");
    String name4=new String("justin");
    System.out.println(name1.equal(name2));//true
    System.out.println(name1.equal(name3));//true
    System.out.println(name3.equal(name4));//true

不可变动字符串

String name1="java";
String name2=name1+"world";
System.out.println(name2);

反编译上面的代码

String s="java";
String s1=(new StringBuilder()).append(s).append("world").toString();
System.out.println(s1);

来看看这个:

String text1="Ja"+"va";
String text2="java";
System.out.println(text1==text2);//true

反编译:

String s="Java";
String s1="java";
System.out.println(s==s1);

这就是为什么输出true

对象数组

public class CashCard {//现金卡类
	protected String id;//代号
	protected double money;//资金
	public CashCard() {}//无参构造函数
	public CashCard(String id, double money) {//有参构造函数
		this.id = id;
		this.money = money;
	}
	public String getId() {//得到代号
		return id;
	}
	public void setId(String id) {//设置代号
		this.id = id;
	}
	public double getMoney() {//查到资金数
		return money;
	}
	public void addMoney(double money) {//增加资金数
		if(money>0) {
			this.money += money;
		}
		else {//如果钱数输入错误
			System.out.println("money you add is wrong");
		}
	}
	public void drawMoney(double money) {//取钱
		if(money<this.money&&money>=0) {//当钱数大于等于0,且取钱数小于资金数时
			this.money-=money;
		}
		else if(money<0) {//当取钱数小于0时
			System.out.println("money you draw is not right!!!");
		}
		else {//当取钱数大于资金数时
			System.out.println("Your money is not enough!!!");
		}
	}
} 
public class IrateCashCard extends CashCard{
	protected double irate;//利率
	IrateCashCard(){}//无参构造函数
	IrateCashCard(String id,double money){//有参构造函数
		super(id,money);//继承父类构造方法
	}
	public double getIrate(){//通过存取的钱数,给定利率
		if(money>0&&money<=1000) {
			this.irate=0.01;
		}
		else if(money>1000&&money<10000) {
			this.irate=0.02;
		}
		else if(money>10000&&money<100000) {
			this.irate=0.04;
		}
		else if(money>100000&&money<1000000) {
			this.irate=0.05;
		}
		else if(money>=1000000){
			this.irate=0.06;
		}
		else {
			System.out.println("your money you put is wrong!");
		}
			return irate;
		}
	public static void main(String[] args) {
		IrateCashCard[] cards = { //创建数组对象
				new IrateCashCard("A001", 1000), 
				new IrateCashCard("A002", 1500),
				new IrateCashCard("A003", 2000),
				new IrateCashCard("A004", 2500), 
				new IrateCashCard("A005", 1000000) };
		cards[0].addMoney(10000);//存10000
		cards[1].drawMoney(200);//取200
		for (IrateCashCard card : cards) {//输出当前5张卡的id与资金数以及利率
			System.out.println(card.id+" "+card.money+" "+card.getIrate());
		}
	}
}
/*输出:
 A001 11000.0 0.04
 A002 1300.0 0.02
 A003 2000.0 0.02
 A004 2500.0 0.02
 A005 1000000.0 0.06*/

可以改进程序 存钱函数addMoney()可以这样写
Scanner scanner=new Scanner(System.in);
cards[1].addMoney(scanner.nextDouble());
这样用户可以键入钱数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值