气温骤降,头疼的厉害。
今天发生了一些难过的事,心情真的不好,状态糟糕透了,但是这件事也激励我要努力学习,加油!
继续学习Java。
1.构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class CashCard {
String number;
int balance;
int bonus;
public CashCard(String number, int balance, int bonus) {
this.number = number;
this.balance = balance;
this.bonus = bonus;
}
}
|
构造函数与类名称同名,不用声明返回类型。构造函数支持函数重载。若没有写构造函数,编译程序会自动加入一个内容为空,参数为空的构造函数。所以新建对象的语法就是这么来的。
1 2 3
| CashCard card = new CashCard();
|
在使用方法重载时要注意自动装箱和拆箱,会依照以下顺序处理:
(1)还没有装箱前可符合变量个数和类型的方法
(2)装箱后才符合的
(3)尝试有不定长度变量并可符合自变量类型的方法
(4)找不到合适的,报错
2.封装对象的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class CashCard {
String number;
int balance;
int bonus;
public CashCard(String number, int balance, int bonus) {
this.number = number;
this.balance = balance;
this.bonus = bonus;
}
void store(int money) {
if (money > 0) {
this.balance += money;
if (money >= 1000) {
this.bonus++;
}
} else {
System.out.print("储值是负的");
}
}
}
|
在这个对象中我写了一个方法在里面,所以每次存钱的时候我就只管调用store
方法,而不需要自己操作数据成员。方法名称要小写,也支持重载。
3.getters和setters
对于上面的代码还有个问题是用户可以直接访问数据成员,这显然是不安全的。我们应该将他们改为private
,但是也要提供一个可靠的方法供用户使用修改数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| class CashCard {
private String number;
private int balance;
private int bonus;
public CashCard(String number, int balance, int bonus) {
this.number = number;
this.balance = balance;
this.bonus = bonus;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public int getBonus() {
return bonus;
}
public void setBonus(int bonus) {
this.bonus = bonus;
}
|
所以有get和set方法,这种写法是固定的。在eclipse中,在空白处单击右键->source->generate Getters and Setters可自动生成。
构造函数的功能其实和get,set方法有一定重复,他们都可以用来赋值,但是用途是不一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class test {
public static void main(String[] args) {
CashCard card = new CashCard("a1",1000,10);
card.setNumber("a2");
card.setBalance(500);
card.setBonus(20);
System.out.print(card.getNumber()+card.getBalance()+card.getBonus());
}
}
|
可以看出,构造函数在一次性赋全部值时比较方便,而set方法则适合对单个值的修改。当然,事无绝对,可以对构造函数进行重载,条条大路通罗马,方法不止一个。
4.一些关键字
(1)private
表示的成员为类私有,用户无法在其他类的代码中直接使用。如果没有声明权限修饰的成员,只有在相同包的类程序代码中才可以直接使用,也就是包范围权限。
(2)如果想在其他的类程序代码中使用包的类或对象成员,则该类或对象必须是公开的,要加public
声明。
(3)使用this
除了被声明为static的地方外,this可以出现在类中的任何地方,在对象建立后,this为这个对象的别名(参考名称)。例如:
1 2 3
| CashCard card = new CashCard("a1",500,20);
|
1 2 3 4 5 6 7 8 9 10 11
| public CashCard(String number, int balance, int bonus) {
this.number = number;
this.balance = balance;
this.bonus = bonus;
}
|
在这里,构造函数中的this指代了新对象card,将传入的参数给了card。
在上面我写到,构造函数可以重载,this在这里也有应用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class Some {
private int a = 10;
private String text = "n.a.";
public Some(int a) {
if (a > 0) {
this.a = a;
}
}
public Some(int a, String text) {
if (a > 0) {
this.a = a;
}
if (text != null) {
this.text = text;
}
}
}
|
两个构造函数中有部分重复的,这不是一个好的代码。所以我们可以在一个构造函数中再次调用另一个构造函数。写成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class Some {
private int a = 10;
private String text = "n.a.";
public Some(int a) {
if (a > 0) {
this.a = a;
}
}
public Some(int a, String text) {
this(a);
if (text != null) {
this.text = text;
}
}
}
|
上面说过this是对象的参考名称,this(a)可以看成是Some(a),这样一来,意义就明确了,就是调用了public Some(int a)
这个构造函数。注意,this()调用只能出现在构造函数的第一行。
有点小细节:
如果在创建对象之后和调用构造函数之前有想要执行的流程可以这么写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class other{
{
System.out.println("对象初始区块");
}
other(){
System.out.println("调用other()构造函数");
}
other(int o){
this();
System.out.println("调用other(int o)构造函数");
}
}
public class Aa{
public static void main(String[] args){
new other(1);
}
}
|
在这里是先执行对象初始区块后在执行指定的构造函数。
(4)final关键字
一旦使用了final就不能更改。有点意思的是:
1 2 3 4 5 6 7 8 9
| public class Something{
final int x;
}
|
对对象成员使用final且不给赋值表示的是延迟对象成员值的指定。所以在构造函数中一定要有对改数据成员指定值的动作。而且,有构造函数重载时,要注意做到每个构造函数都有指定值或默认值,不能有一个没有,因为有可能调用到那个没有指定值或默认值的构造函数。
(5)static
对于一个类,可以根据他建立多个对象,每个对象都具有类中规定的数据成员。例如我建立两个CashCard对象,那么就有六个数据成员。但是有的时候,类中的数据是个常数,例如Pi,这样的数据显然不需要每个都拥有。那么可以这么写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Ball{
double radius;
static final double PI = 3.1415;
static double toRadians(double angdeg){
return angdeg * (Ball.PI/180);
}
}
|
被声明为static的成员,是将类名称作为名称空间,不会让个别对象拥有,而是属于类。
1 2 3 4 5
| System.out.println(Ball.PI);
System.out.println(Ball.toRadians(100));
|
类比到System.out.println
,out是System类的,查看API文档发现out是java.io.PrintStream类型。
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Ball{
double radius;
static void doSome(){
double r=this.radius;
}
}
|
由于static是属于类的,所以在static中使用this是不对的。就是说,在静态区访问非静态区是不对的,最简单的理解就是this是在建立对象后的别名,但是在上面的代码中,我压根就没建立对象。
下面这种也是不对的;
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Ball{
double radius;
static void doSome(){
double r=radius;
}
}
|
虽然没写this,但实际隐含了this。什么意思?假如我新建两个对象,例如ball1和ball2,在类中调用doSome,没法确定用哪个radius。静态的对非静态的调用就是有这种问题:调用的东西可能根本还没建立或者建立了多个。this有关的东西不止这点,后面还会再出现。
用import可以导入包,而使用import static则可以把静态成员导入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import static java.lang.System.in;
import static java.lang.System.out;
import static java.util.Scanner;
public class ImportStatic{
public static void main(String[] args){
Scanner scanner = new Scanner(in);
out.print("name?");
out.printf("%s hello! %n",scannner.nextline());
}
}
|
5.不定长度变量
观察System.out.printf("%d",10);
,printf方法的变量是不定个数的。在自己写方法时也可以做到这样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class MathTool{
public static int sum(int... number){
int sum = 0;
for(int number : numbers){
sum+=number;
}
return sum;
}
}
|
当使用这种方法后,就可以这样调用System.out.print(MathTool.sum(1,2,3));
这种写法的本质是将参数改为一个数组,前面的调用相当于MathTool.sum(new int[] {1,2,3})
。在参数不只有不定长度变量而还有其它的变量时,不定长度参数要放在最后一个,也不允许声明两个以上不定长度变量。
6.内部类
简单说,就是在类里面再定义一个类。
1 2 3 4 5 6 7 8 9
| class Some{
class Othes{
}
}
|
要使用Some中的Other类,则必须先建立Some的实例:
1 2 3 4 5
| Some s = new Some();
Some.Other o = s.new Other();
|
内部类也可以使用public,protected或private声明。一个被声明为static的内部类,通常是将外部类作为名称空间,所以可以这么写:Some.Other o = new Some.Other();
内部static类可以存取外部static类,外部非static不可以。
方法中也可以声明类,通常用于方法中的计算,外部无法使用。
这部分我没怎么理解透彻。
7.传值调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class CallByValue{
public static void main(String[] args){
Customer c1 = new Customer("Justin");
some(c1);
System.out.println(c1.name);
Customer c2 = new Customer("Justin");
some(c2);
System.out.println(c2.name);
}
static void some(customer c){
c,name = "John";
}
static void other(Customer c){
c = new Customer("Bill");
}
}
class Customer{
String name;
Customer(String name){
this.name = name;
}
}
|
结果是:
首先建立两个对象,c1&c2,name都是Justin。some(c1)将c1(参考而不是整个对象)传递给some()方法的参数c,也就是说现在是c和c1一起指向一个Customer对象。接着,”John”被要求给c参考的对象。
但是在other()方法中,原本c和c1一起指向一个Customer对象,但是c又被要求指向一个新的name是”Bill”的对象,而c1并没有被更改什么。
说实话,上面这顿是Java学习笔记中的讲法,很不清楚,再贴两个链接,写的清晰明了。
https://www.cnblogs.com/chen-kh/p/6696303.html
https://blog.csdn.net/zzp_403184692/article/details/8184751