2.1、构造方法的基本概念
构造方法名与类名完全相同并且没有返回值类型,连void都不允许有。
格式:
class 类名{ class Person{
类名(形参列表){ Person(){ -Person类中的构造方法
构造方法体; }
} }
}
默认构造方法:
当一个类中没有定义任何构造方法时,编译器会自动添加一个无参空构造方法,叫做默认/缺省构造方法,如:Person(){};
若类中出现了构造方法,则编译器不在提供任何形式的构造方法。
/*
编程实现Person类的定义
*/
public class Person{
String name;
int age;
//自定义构造方法
Person( String s, int i){
name = s;
age = i;
System.out.println( "我就是自定义的构造方法" );
}
//自定义一个无参构造函数
person(){
;
}
//自定义成员方法实现所有特征的打印
void show(){//隐藏了this关键字,this关键字代表当前正在调用的对象
System.out.println( "我叫" + this.name + ",今年" + age + "岁了");
}
public static void main( String[] args){
//1、声明一个Person类型的引用指向Person类型的对象
Person p1 = new Person( "zhangfei", 30 );
//2、打印特征
p1.show(); //默认值 null 0
Person p2 = new Person("guanyu", 35);
p2.show();
Person p3 = new Person();
p3.show();
}
}
样例:编程实现Point类的定义并向Point类中添加构造方法
/*
编程实现Point类的定义并向Point类中添加构造方法
*/
public class Point{
int x;//定义一个成员变量来描述点的横坐标
int y;//定义一个成员变量来描述点的纵坐标
//定义一个有参构造函数来实现坐标初始化
Point( int i, int j ){
x = i;
y = j;
}
//定义一个无参构造函数,默认横纵坐标为0
Point(){//函数体内也可以不写
x = 0;
y = 0;
}
//自定义成员方法实现点的横纵坐标打印
void show(){
System.out.println( "横坐标为:"+ x + "纵坐标为:" + y );
}
public static void main( String[] args ){
Point p1 = new Point();//调用无参构造函数
p1.show(); // 0 0
Point p2 = new Point(5, 10);//调用有参构造函数
p2.show(); // 5,10
}
}
从上面可以看到,有两个函数名称相同的构造方法,从而引出方法重载的概念。
**方法重载:**若方法名称相同,参数列表不同,这样方法之间构成重载。
public class OverLoadTest{
//自定义成员方法
void show(){
System.out.println("show()");
}
void show(int i){//体现在方法参数个数不同
System.out.println("show(int)");
}
void show(int i, double j){//体现在方法参数个数不同
System.out.println("show(int, double)");
}
void show(int i, int j){//体现在方法参数类型不同
System.out.println("show(int, int)");
}
void show( double j, int i){//体现在方法参数顺序不同
System.out.println("show( double, int )");
}
/*
void show( double a, int b){//出错:与参数变量名无关
System.out.println("show( double, int )");
}
int show( double a, int b){//出错:与返回值类型无关
System.out.println("show( double, int )");
}
*/
public static void main( String[] args ){
//1、声明OverLoadTest类型的引用指向该类型对象
OverLoadTest ot = new OverLoadTest();
//2、调用show方法
ot.show();
ot.show( 1 );
ot.show( 1, 3.14 );
ot.show( 1, 2 );
}
}
总结:方法重载的主要体现形式:在参数的个数不同,参数的类型不同、参数的顺序不同,与返回值类型和形参变量名无关,但建议返回值类型最好相同。
判断方法能否构成重载的核心:调用方法时能否加以区分。
方法重载的实际意义:调用者只需要记住一个方法名就可以调用各种不同的版本,来实现不同的功能。
例子:println方法,可以打印不同的数据类型的信息。
2.2 this的基本概念
若在构造方法中出现了this关键字,则代表当前正在构造的对象。
若在成员方法中出现了this关键字,则代表当前正在调用的对象。
this关键字本质上就是当前类类型的引用变量
//编程实现this关键字
public class ThisTest{
//自定义构造函数
ThisTest(){
//this代表当前正在构造的对象
System.out.println( "构造方法中:this = " + this);
}
//自定义成员函数
void show(){
//this代表当前正在调用的对象
System.out.println( "成员方法中:this = " + this );
}
public static void main( String[] args ){
//1、声明一个ThisTest类型的引用指向该类型的对象
ThisTest tt = new ThisTest();
//2、调用show方法
tt.show();
System.out.println( "main方法中:tt = " + tt );
}
}
//上面三次打印都是一样的
工作原理:在构造函数中和成员方法访问成员变量时,编译器会加上this.的前缀,而this.相当于汉语中”我的“,当不同对象调用同一个方法时,由于调用对象不同会导致this关键字不同,从而this.方式访问结果也就随之不同。
this使用方式:
- 当局部变量名与成员变量名相同时,在方法体中会优先使用局部变量(就近原则),若希望使用使用成员变量,则需要在成员变量的前面加上this.的前缀,明确要求该变量是成员变量。(重点)
- this关键字除了可以通过this.的方式调用成员变量和成员方法之外,还可以作为方法的返回值。
- 在构造方法的第一行可以使用this()的方式来调用本类中的其他构造函数(了解)
//编程实现Boy类的定义
public class Boy{
String name;
//自定义无参构造函数
Boy(){
//调用本类中的有参构造函数
//this("无名");//必须放在第一行
System.out.println("无参构造函数");
}
Boy(String name){
//调用本类中的无参构造函数
this();//只能与上面的this("无名")选择一个使用
System.out.println("有参构造函数");
this.name = name;
}
//自定义成员方法实现特征打印
void show(){
System.out.println( name );
}
public static void main(){
//1、使用无参方式构造对象并打印特征
Boy b1 = new Boy();
b1.show();
//2、使用有参方式构造对象并打印特征
Boy b2 = new Boy();
b2.show();
}
}
引用变量注意事项:
- 引用类型变量用于存放对象地址,可以给引用类型赋值为null,表示不指向任何对象。
- 当某个引用类型变量为null时无法对对象实施访问(因为其没有指向任何对象)。此时,如果通过引用访问成员变量或调用方法,会产生NullPointerException(空指针)异常。
几种异常:空指针异常,算法异常,数组下标越界异常。
案例:阶乘计算
//阶乘计算
public class JieCheng{
int show( int n ){
//方法一:递推法
/*
int num = 1;
for( int i = 1; i < n; i++ ){
num *= i;
}*/
//方法2:递归(在方法体内部调用本身,就是递归)
//当n的数值为1时,则阶乘结果就是1
if( 1 == n ){
return 1;
}
return n * show( n-1 );
}
public static void main( String[] args ){
JieCheng jc = new JieCheng();
int res = jc.show( 5 );
System.out.println( "计算结果是:" + res );//120
}
}
递归:方法体调用自身。
注意事项:使用递归必须有递归的规律以及退出条件;
使用递归必须使得问题简单化而不是复杂化;
若递归影响程序的执行性能,则使用递推取代之。
案例:实现斐波那契数列中第n项并返回
public class FeeTeat{
int show( int n ){
//1、使用递归的方式计算
//当n = 1或者n = 2时,结果为1
/*if( 1 == n || 2 == n ){
return 1;
}
return show( n - 1) + show( n - 2); */
//法2:使用递推迭代
int ia = 1;
int ib = 1;
for( int i = 3; i <= n; i++ ){
int ic = ia + ib;//使用一个变量记录它两的值
ia = ib;//向前移动ia
ib = ic;//向前移动ib
}
return ib
}
public static void main( String[] args ){
FeeTeat ft = new FeeTeat();
int res = ft.show( 5 );
System.out.println( "结果为:" + res );
}
}
2.3 封装(封装类)
通常需要对成员变量进行密封包装处理,来隐藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装。
封装实现流程:
1. 私有化成员变量,使用private关键字修饰。(private关键字修饰表示私有的含义,也就是该成员变量只能在当前类的内部使用。)
2. 提供公有的get和set方法,并在方法体中进行合理判断。(使用public关键字修饰表示公有的含义,也就是该方法可以在任意位置使用)
3. 在公有的构造方法中调用set方法进行合理值得判断。
4
//编程实现Student类的封装
public class Student{
//1、私有化成员变量
private int id;
private String name;
//3、在公有的构造方法中调用set方法进行合理值得判断。
public Student( int id, String name ){
setId( id );//this.id = id;
setName( name );//this.name = name;
}
//2、提供公有的get和set方法
public int getId(){
return id;
}
public int setId( int id ){
if( id > 0 ){
this.id = id;
}else{
System.out.println("学号输入不合理!");
}
}
public int getName(){
return name;
}
public int setName( String name ){
this.name = name;
}
//自定义成员方法实现特征打印
//什么修饰符都没有叫做默认的访问权限,级别介于private和public之间
void show(){
System.out.println( "我是"+name + "我的学号是" + id );
System.out.println( "我是"+getName() + "我的学号是" + getId() );
}
}
public class StudentTest{
public static void main(){
Student s1 = new Student();
//s1.id = 1001;//错误,不可直接赋值访问
s1.setId(1001);
s1.setName("zhangfei");
}
}
JavaBean特点(类似封装类)
- 类是公共的
- 有一个无参得公共得构造器
- 有属性,且有对应得get、set方法