构造函数详解

article/2025/9/14 4:10:32

构造函数详解

类的6个默认的成员函数

在这里插入图片描述

构造函数的概念:
  • 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次。
构造函数的特性
  • 函数名与类名相同。
  • 无返回值。
  • 编译器自动调用对应的构造函数。
  • 构造函数可以重载。
为什么要引出构造函数这一概念
  • 看下面的代码,对于Date类,可以通过InitDate公有的方法给对象设置内容,但是如果每次创建对象都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?
  • 现在我们的需求就是不通过对象去调用初始化对象的数据,我们希望当这个对象创建出来的时候,他就已经是具有一定的初始值的,那么如何做到我们现在的这个需求的呢?
  • 由此,引入了构造函数这一个概念,如下所示:
#include<iostream>
using namespace std;
class Date
{
public:void InitDate(int year, int month, int day)   //进行初始化的操作{_year = year;_month = month;_day = day;}void PrintDate()   //打印进行检测{cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1, d2, d3;d1.InitDate(2020, 4, 30);d1.PrintDate();d2.InitDate(2020, 4, 29);d2.PrintDate();d3.InitDate(2020, 4, 28);d3.PrintDate();
}
构造函数的功能
  • 需要注意的一点是,虽然构造函数叫"构造"函数,但是构造函数并不是用来构造对象的,构造函数的功能是用来完成对象的初始化的
#include<iostream>
using namespace std;
class Date
{
public://无参的构造函数Date()   //构造函数  ,没有返回值{cout << "Date()" << this << endl;   //打印this是为了看当前构造的是哪一个对象//把对象的地址打印出来}Date(int year, int month, int day){_year = year;_month = month;_day = day;}//两个构造函数形成了重载//一个是没有参数的构造函数,一个是具有三个参数的构造函数 //创建几个对象,编译器就会调用几次构造函数//调用构造函数的次数与对象的次数是相同的//因为构造函数调用的时机就是在创建对象的时候调用void InitDate(int year, int month, int day)   //进行初始化的操作{_year = year;_month = month;_day = day;}void PrintDate()   //打印进行检测{cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1, d2, d3;Date d4(2020, 4, 27);Date d5();     //并不是创建了一个对象//这是一个函数声明,相当于我是有一个函数名称//为d5的函数,这个函数的返回值类型是Date类型,没有参数d1.InitDate(2020, 4, 30);d1.PrintDate();d2.InitDate(2020, 4, 29);d2.PrintDate();d3.InitDate(2020, 4, 28);d3.PrintDate();d4.PrintDate();}
如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成
  • 当然,前提是,只有用户没有显示定义构造函数的时候,编译器才会去生成默认的构造函数
#include<iostream>
using namespace std;
class Date
{
public://无参的构造函数//Date()   //构造函数  ,没有返回值//{//	cout << "Date()" << this << endl;   //打印this是为了看当前构造的是哪一个对象//	//把对象的地址打印出来//}//Date(int year, int month, int day)//{//	_year = year;//	_month = month;//	_day = day;//}//两个构造函数形成了重载//创建几个对象,编译器就会调用几次构造韩素void InitDate(int year, int month, int day)   //进行初始化的操作{_year = year;_month = month;_day = day;}void PrintDate()   //打印进行检测{cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;//编译器生成的构造函数是默认的构造函数//默认的构造函数一定是无惨的//如果说,用户定义构造函数了,编译器就不会生成的//如果这个时候再创建一个带有三个参数的对象的话//就一定是不会创建成功的//对象创建成功了,就说明是有默认的构造函数存在的return 0;
}

在这里插入图片描述

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数

在这里插入图片描述

#include<iostream>
using namespace std;
class Date
{
public://无参的构造函数Date()   //构造函数  ,没有返回值{cout << "Date()" << this << endl;   //打印this是为了看当前构造的是哪一个对象//把对象的地址打印出来}//全缺省的构造函数Date(int year=2000, int month=1, int day=1){_year = year;_month = month;_day = day;}//两个构造函数形成了重载//创建几个对象,编译器就会调用几次构造函数void InitDate(int year, int month, int day)   //进行初始化的操作{_year = year;_month = month;_day = day;}void PrintDate()   //打印进行检测{cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;
}
  • 上面的代码,是会报错的,无法通过编译,报错的内容是—“Date::Date”:对重载函数的调用不明确,因为上面的代码中,有两个默认的构造函数,因为不带参数的构造函数和全缺省的构造函数都被看为默认的构造函数,所以说,现在有两个构造函数,编译器不知道到底要去调用哪个构造函数,所以说,就会报错,所以说,默认的构造函数只能存在有一个,下面的代码就可以通过编译了
#include<iostream>
using namespace std;
class Date
{
public://全缺省的构造函数Date(int year = 2000, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//两个构造函数形成了重载//创建几个对象,编译器就会调用几次构造函数void InitDate(int year, int month, int day)   //进行初始化的操作{_year = year;_month = month;_day = day;}void PrintDate()   //打印进行检测{cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;
}
关于编译器生成的默认成员函数,很多人会有疑惑:在我们不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默认构造函数,但是d对象year/month/_day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用?
  • 解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语法已经定义好的类型:如int/char…,自定义类型就是我们使用class/struct/union自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数
class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}
成员变量的命名风格
// 我们看看这个函数,是不是很僵硬?
class Date
{
public:Date(int year){// 这里的year到底是成员变量,还是函数形参?year = year;}
private:int year;
};
// 所以我们一般都建议这样
class Date
{
public:Date(int year){_year = year;}
private:int _year;};
// 或者这样。
class Date
{
public:Date(int year){m_year = year;}
private:int m_year;
};
// 其他方式也可以的,主要看公司要求。一般都是加个前缀或者后缀标识区分就行。

在这里插入图片描述

再谈构造函数
问题:构造函数体中的语句是不是初始化?

在这里插入图片描述

  • 赋值和初始化的区别----赋值是可以进行多次赋值的,但是初始化的话,只能进行一次的初始化操作
  • 可以通过如下的方式进行验证,验证到底是初始化还是赋值
    在这里插入图片描述
  • 发现上述的代码编译成功了,所以说明构造函数体中不是初始化,而是赋值
    在这里插入图片描述
  • 上述代码中a为const类型的变量,对代码进行编译之后,发现代码无法通过编译,也就更加证实了,构造函数体内是赋值而并非是初始化,因为const类型的成员无法进行赋值的操作
构造函数体赋值
  • 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值
  • 构造函数最主要是用来完成对象的初始化的工作的,但是我们在构造函数函数体内进行的赋值操作虽然说也可以把给参数的值放到对象里面去,但是构造函数函数体里面不是初始化,因为是赋值操作,那么我们如何来判断构造函数函数体里面是赋值还是初始化呢?我们可以使用一个在定义的时候必须进行初始化的东西来判断构造函数函数体里面到底是赋值还是初始化。那么很容易想到的就是引用在定义的时候必须进行初始化操作,那么我们可以在private定义的变量中引入一个引用变量,给了引用变量之后是会报错的,那么就说明构造函数函数体里面的操作其实是赋值而不是初始化的操作
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
  • 虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称作为类对象成员的初始化,构造函数体中的语句只能将其称作为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值
  • 所以得出结论—构造函数函数体中是赋值不是初始化
初始化列表的概念
  • 构造函数具有初始化列表,并且只有工造函数具有初始化列表,别的函数都没有初始化列表
  • 初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式
#include<iostream>
using namespace std;
class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){cout << "Date(int year, int month, int day)" << endl;}
private:int _year;int _month;int _day;
};

在这里插入图片描述

  • 那么如何验证初始化列表是初始化而不是赋值呢?
  • 因为我们是知道的,赋值是可以进行多次的,但是初始化只能初始化一次,那么我们就可以利用这个性质,在初始化列表中让一个变量出现多次,如果代码报错的话,那么就说明初始化列表是初始化而不是赋值了,如下所示,下面的代码时会报错的
#include<iostream>
using namespace std;
class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day),_day(day){cout << "Date(int year, int month, int day)" << endl;}
private:int _year;int _month;int _day;
};
  • 报错内容是_day已经初始化了
    在这里插入图片描述
  • 初始化只能初始化一次,如果多次进行初始化操作的话,代码就会报错
  • 就好像是一个人不能多次出生是一样的道理
初始化列表的功能
  • 初始化列表就是专门就是为了对类中各个成员变量进行初始化的操作,而初始化呢他不是可以初始化两次的,所以一个变量如果初始化两次的话就会出错。因为在对变量进行初始化的时候需要为变量开辟内存空间,如果已经为一个变量开辟了内存空间的话,就不需要为那个变量再次开辟内存空间了。 一个变量开辟两个空间肯定是有问题的
  • 初始化列表并没有规定各个变量出现的次序,就算初始化列表的次序和形参出现的次序是不一样的,代码也是不会报错的,所以说,初始化列表并没有强制规定参数的次序要和形参的次序是一样的。但是一般情况下不建议这么做,防止出现像这样的问题
    在这里插入图片描述
    在这里插入图片描述
    为什么month会是随机值呢,因为编译器先去初始化year,然后初始化year完成之后,编译器开始去初始化month,但是初始化列表给的是用day去初始化month,但是此时day并没有进行初始化的操作,所以最终看出,month为随机值。
注意事项
  • (1)初始化列表中成员的出现次序,不代表其真正的初始化次序
  • (2)成员变量在初始化列表中的初始化次序为其在类中的声明次序
  • 建议:最好不要使用成员初始化成员
  • 虽然说我们可以把_day写在_month的前面,但是我们在初始化的时候,还是先去初始化的_month然后再去初始化的_day
  • 编译器是不会按照我们所给出的初始化的顺序来进行初始化的,编译器是按照形参出现的顺序来进行初始化操作的
拷贝构造函数也可以有初始化列表
#include<iostream>
using namespace std;
class Date
{
public:Date(const Date& d): _year(d._year), _month(d._month), _day(d._day){// 		_year = d._year;// 		_month = d._month;// 		_day = d._day;cout << "Date(Date&):" << this << endl;}
private:int _year;int _month;int _day;
};
引用变量以及const类型的变量的注意事项
  • 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
  • 类中包含以下成员,必须放在初始化列表位置进行初始化:(在构造和拷贝构造的地方都需要进行初始化)
  • (1)引用成员变量
  • (2)const成员变量
    在这里插入图片描述
#include<iostream>
using namespace std;
class Date
{
public:
#if 0// 初始化列表Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){// 构造函数体中是赋初值不是初始化
// 		_year = year;
// 		_month = month;
// 		_day = day;//r = _day;cout << "Date(int,int,int):" << this << endl;}
#endif// 初始化列表// 1. 初始化列表中成员的出现次序,不代表其真正的初始化次序// 2. 成员变量在初始化列表中的初始化次序为其在类中的声明次序// 建议:最好不要使用成员初始化成员Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day), _r(_day), _a(_day){// 构造函数体中是赋初值不是初始化// 		_year = year;// 		_month = month;// 		_day = day;//r = _day;cout << "Date(int,int,int):" << this << endl;}Date(const Date& d): _year(d._year), _month(d._month), _day(d._day), _r(d._r), _a(d._a){// 		_year = d._year;// 		_month = d._month;// 		_day = d._day;cout << "Date(Date&):" << this << endl;}// d1 = d2 = d3;Date& operator=(const Date& d){cout << this << "=" << &d << endl;if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}~Date(){cout << "~Date():" << this << endl;}int _year;int _month;int _day;int& _r;const int _a;
};
  • (3)类类型成员(该类没有默认构造函数)
#include<iostream>
using namespace std;
class Time
{
public:Time(int hour, int minute, int second): _hour(hour), _minute(minute), _second(second){}private:int _hour;int _minute;int _second;
};class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day), _t(0, 0, 0)//, _t()   //调用无参的默认的构造函数{cout << "Date(int,int,int):" << this << endl;}private:int _year;int _month;int _day;Time _t;//如果没有上面的_t(0, 0, 0),直接给出Time_t是会报错的,原因在于//声明了一个time类的对象t,那么这个对象t一定是需要进行初始化的//那么编译器会默认去Time类中寻找没有参数的构造函数,但是Time类此时是没有//显示给出无参的构造函数的,所以就会出错//那么我们为了可以正确的创建出来这个Time类类型的对象的话,那么我们就需要给出来一个有参数的//就好比说_t(0, 0, 0),就可通过编译了
};int main()
{//Date d(2019, 3, 24);Date d;return 0;
}
  • 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。(没写并不代表没有,还是会去调用相应的函数的)
  • 其实也就是说,就算你的构造函数函数体里面什么都没有,他也是会优先去执行构造函数的初始化列表,所以,尽量还是使用初始化列表来进行初始化操作。
  • 调试起来的话,会首先停在构造函数函数名的位置上,并没有直接走到了函数体的内部
  • 看起来构造函数没有写初始化列表,但是需要注意,没有写并不代表没有,因为如果用户没有写的话,其实编译器是会自动去加上的,只不过一般情况下成员变量是用随机值进行初始化的
  • 要先初始化好,才能进入到构造函数的函数体中
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
#include<iostream>
using namespace std;
class Time
{
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){cout << this->_hour << endl;}void TestFunc(){}private:int _hour;int _minute;int _second;
};class Date
{
public:Date(int year = 1900, int month = 1, int day = 1)// 		: _year(year)// 		, _month(month)// 		, _day(day)//, _t()   //调用无参的默认的构造函数{cout << "Date(int,int,int):" << this << endl;}private:int _year;int _month;int _day;Time _t;
};

在这里插入图片描述
在这里插入图片描述

  • 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关,也就是说,不是按照我给的初始化列表的次序来进行初始化操作的,编译器是按照声明的次序来进行初始化的(上面已经提到过了)

提问,在初始化列表中如何知道对象已经构造好了?

  • 就是在构造函数的初始化列表完成之后,去打印一下this,如果代码可以正常的通过编译,那么就说明我的对象是构造好了的
#include<iostream>
using namespace std;
class Time
{
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){cout << this<< endl;    //我的意图是要去打印this,然后发现代码可以正常通过编译//那么,也就是说,此时,我的对象已经构造好了}
private:int _hour;int _minute;int _second;
};
两个问题
在构造函数有没有把对象的地址传递过去呢?
  • 对象的地址一定是传递过来了的,如果对象的地址没有传递过来的话,那儿我怎么知道当前构造的是那个对象呢?所以说对象的地址一定是已经传递过来了的
    在这里插入图片描述
  • 008560677 把t的首地址放到了exc寄存器里面,然后去调用Time类的函数
  • 在构造函数调用之前,对象是不存在的,因为构造函数的目的就是用来初始化对象的,虽然对象本身是并不存在的,但是对象的空间是存在的,所以也就是说,在我们没有调用构造函数之前,我们就已经有了一段空间了,因为编译器是要进行编译的,所以他必须提前计算出这个对象需要多大的栈空间
    在这里插入图片描述
  • 定义了两个对象,所以编译器必须要在编译期间计算出这两个对象的大小,因为不可能做到一边运行一边修改,所以说,必须要提前计算好,在编译的时候是不会调用构造函数的,是在运行的时候去调用的
在构造函数的初始化列表的位置可不可以使用this指针呢?

在这里插入图片描述

  • 在构造函数初始化列表的位置还不能使用构造函数,因为this是指向当前对象的,初始化列表的位置,当前对象还并没有构造好,所以还是不能使用的,还没有真正的区划分空间。但是在函数体里面是完全可以,因为对象已经完全的初始化完成了,是 可以正常去使用的
#include<iostream>
using namespace std;
class Time
{
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){cout << this->_hour << endl;}void TestFunc(){}private:int _hour;int _minute;int _second;
};class Date
{
public:Date(int year = 1900, int month = 1, int day = 1)// 		: _year(year)// 		, _month(month)// 		, _day(day)//, _t()   //调用无参的默认的构造函数{cout << "Date(int,int,int):" << this << endl;}private:int _year;int _month;int _day;Time _t;
};int main()
{// 在编译器编译期间,已经为main分配好了栈空间// 该空间中已经包含了函数体中的局部对象Date d;    // 在构造函数调用之前,对象是不存在的Time t;t.TestFunc();return 0;
}
结论:也就是说对象的空间早就已经给好了,只不过缺的是构造函数,构造函数的功能就是把对象中各个成员变量给其初始化好就可以了
构造函数的功能
  • 构造函数不仅就有初始化成员变量的功能,还具有类型转化的功能
    在这里插入图片描述
    在这里插入图片描述
  • 因为单参的构造函数代码可读性太差,所以我们一般就把单参的构造函数的类型转换的功能给他禁止掉,用下面的关键字进行禁止
explicit关键字
  • 构造函数不仅可以构造与初始化对象,对于单个参数的构造函数,还具有类型转换的作用
    在这里插入图片描述
#include<iostream>
using namespace std;
class Date
{
public:Date(int year): _year(year){cout << "Date(int,int,int):" << this << endl;}Date& operator=(const Date& d){return *this;}private:int _year;int _month;int _day;
};int main()
{Date d(2019);d = 2020;   //一个是日期类型的变量,一个是整形的变量,在我们之前想的是,这时不能通过编译的//但是没想到,这样的代码是可以通过编译的,原因在于// 2020---> 通过单参构造函数--->临时对象//也就是说构造函数具有类型转换的功能,本来是一个int类型,然后被转换了// 用一个整形变量给日期类型对象赋值// 实际编译器背后会用2020构造一个无名对象,最后用无名对象给d1对象进行赋值//但是一般情况下,会把这种类型转换禁止掉,那么如何来禁止呢?//禁止的方法就是在构造函数前面加上一个explicit关键字return 0;
}
  • 上述代码可读性不是很好,用explicit修饰构造函数,将会禁止单参构造函数的隐式转换。
#include<iostream>
using namespace std;
class Date
{
public:explicit Date(int year): _year(year){cout << "Date(int,int,int):" << this << endl;}Date& operator=(const Date& d){return *this;}private:int _year;int _month;int _day;
};int main()
{Date d(2019);d = 2020;   // 2020---> 通过单参构造函数--->临时对象return 0;
}
之前说过的几个默认的构造函数,如果我么没有显示给出的话,编译器会生成默认的
#include<iostream>
using namespace std;
class Date
{
private:int _year;int _month;int _day;
};
int main()
{Date d;return 0;
}
  • 问题来了,什么时候编译器会生成默认的?-------答案就是—>如果编译器感觉自己需要的时候就会生成,那么问题又来了,什么才是编译器需要的时候(一共有四种场景)
#include<iostream>
using namespace std;
class Time
{
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){cout << this->_hour << endl;}Time(Time&){}Time& operator=(Time& t){return *this;}~Time(){}private:int _hour;int _minute;int _second;
};class Date
{
public:// 	Date()// 	{}/*Date(Date& d): _t(d._t){}*/private:int _year;int _month;int _day;Time _t;
};
int main()
{Date d1; // 日期类的构造函数 // Time()Date d2(d1);  // Time(Time&)--->找个调用位置--->Date类的拷贝构造函数中Date d3;d3 = d1;return 0;
}
  • (1)现在有A类和B类两个类,B类中包含A类的对象,A类中有缺省的构造函数,B类中没有定义任何的构造函数,编译器此时就会生成默认的构造函数
  • (2)Time(Time&)—>找个调用位置—>Date类的拷贝构造函数中
  • (3)赋值也是一样的
    在这里插入图片描述
    在这里插入图片描述

http://chatgpt.dhexx.cn/article/bBLWjSJI.shtml

相关文章

C++中的指针类型与构造函数,析构函数

1. 指针类型的作用 1.1 指针取出字节 任何类型的指针占用的空间大小都是相同的 &#xff08;32位CPU是4字节&#xff1b;64位CPU是8字节&#xff09; 既然任何类型的指针占用的空间大小都是相同的&#xff0c;为什么指针还需要类型呢&#xff1f; 指针只是指向了一个内存地址…

c++拷贝构造函数

一. 什么是拷贝构造函数 首先对于普通类型的对象来说&#xff0c;它们之间的复制是很简单的&#xff0c;例如&#xff1a; int a 100; int b a; 而类对象与普通对象不同&#xff0c;类对象内部结构一般较为复杂&#xff0c;存在各种成员变量。 下面看一个类对象拷贝的简单…

C++构造函数

文章目录 1 构造函数的定义及特征2 默认构造函数2.1 合成的默认构造函数2.1.1 默认初始化2.1.2 合成的默认构造函数初始化类成员变量的规则2.1.3 有些场合不能使用合成的默认构造函数 2.2 全缺省的默认构造函数&#xff08;参数都为默认实参的构造函数&#xff09; 3 构造函数初…

C++ 构造函数详解

目录 0. 什么是构造函数 1. 默认构造函数 2. 一般构造函数 3. 拷贝构造函数 4. 转换构造函数 5. 移动构造函数 0. 什么是构造函数 在定义类的成员函数的时候&#xff0c;一般的成员函数与普通的全局函数没有太大的区别&#xff0c;在定义函数的时候都需要说明要返回的类…

【C++要笑着学】类的默认成员函数详解 | 构造函数 | 析构函数 | 构造拷贝函数

&#x1f525; &#x1f525; &#x1f525; &#x1f525; &#x1f525; 火速猛戳订阅 &#x1f449; 《C要笑着学》 &#x1f448; 趣味教学博客 &#x1f525; &#x1f525; &#x1f525; &#x1f525; &#x1f525; [ 本篇博客热榜最高排名&#xff1a;7 ] 写在前…

JSF 文档参考

转自&#xff1a;http://blog.csdn.net/ontheway20/article/details/38532241 A4J 用户指南 目录 1. 介绍 2. 开始使用Ajax4jsf 环境需求 下载Ajax4jsf 安装 简单的 AJAX Echo 项目 JSP 页面 数据 Bean faces-config.xml Web.xml 部署 3. Ajax4jsf 框架的基本概念 介绍 结构概…

IDEA 2020.2 部署JSF项目

目录 一、用Glassfish部署JSF项目 1、下载glassfish 2、配置glassfish环境变量 3、修改jdk环境变量 4、测试glassfish是否可以正常启动 5、在IDEA中创建一个JSF项目 6.问题&#xff1a;部分标签元素无法显示 二、用tomcat部署JSF项目 1、新建项目或者模块&#xff0c;…

JSF教程(1)——简介 + HelloWorld

在写第一个HelloWorld之前先来宏观的了解一下JSF&#xff0c;也许你之前使用过Struts&#xff08;1或者2&#xff09;&#xff0c;SpringMVC&#xff0c;甚至于直接采用JSPServelet开发过web层。JSF与这些最大的不同是JSF是基于一种以组件为中心的用户界面&#xff08;UI&#…

JSF程式

概述&#xff1a; jsf使用spring的依赖注入的思想使得页面和业务逻辑更好的分离开来&#xff0c;页面与页面的跳转&#xff0c;逻辑关系&#xff0c;页面与后台不同的beans的对应和操作都是通过faces-config.xml文件来说明和配置。对程序员的要求不高&#xff0c;页面程序员可…

谈谈京东的服务框架JSF

谈谈京东的服务框架 最近由于在实习期间接触到了京东的自研服务框架JSF&#xff0c;简称“杰夫”&#xff0c;目前我写的一些新功能里面调用的下游接口就是杰夫提供的。现有有很多高效的服务框架&#xff0c;如阿里巴巴的Dubbo配合Apache的ZooKeeper&#xff0c;那么为什么京东…

JSF 转换与验证

在本文中&#xff0c;我们将介绍 JSF 转换和验证框架的概念&#xff0c;它比您所想的要容易使用得多&#xff0c;也灵活得多。 首先我们将介绍应用于 JSF 生命周期的转换和验证过程&#xff0c;然后展示一个简单的 JSF 应用程序中的默认转换和验证过程。接着将展示如何创建和插…

JSF----------基础知识初解

初次学习JSF,对其基础进行了一些学习与整理。 JSF(JavaServer Faces)它是一个基于服务器端组件的用户界面框架。 它用于开发Web应用程序。 它提供了一个定义良好的编程模型&#xff0c;由丰富的API和标签库组成。最新版本JSF 2使用Facelets作为其默认模板系统。 它是用Java编写…

JSF详解

1&#xff0e; 结构&#xff1a; a) 结构图&#xff1a; b) 说明&#xff1a;JSF以MVC模式为基础&#xff0c;与Struts不同&#xff0c;JSF的目标是希望以一个与Swing相类似的方式来开发网页&#xff0c;因此&#xff0c;从JSF的结构图当中&#xff0c;他的核心…

JSF框架整理(一)

一、框架简介 JavaServer Faces (JSF) 是一种用于构建Java Web 应用程序的标准框架&#xff0c;它提供了一种以组件为中心的用户界面&#xff08;UI&#xff09;构建方法&#xff0c;从而简化了Java服务器端应用程序的开发。 典型的JSF应用程序包含下列部分&#xff1a; 一组J…

JSF简介

JSF简介 一、 什么是 JSF &#xff1a; JavaServer Faces (JSF) 是一种用于构建 Web 应用程序的新标准 Java 框架。它提供了一种以组件为中心来开发 Java Web 用户界面的方法&#xff0c;从而简化了开发。 JavaServer Faces于2004年三月1.0版正式提出&#xff0c;清楚的将Web应…

JSF概述

1. JSF简洁 JSF是一种以组件为中心&#xff0c;遵循MVC设计模式的一种框架。 Web引用程序开发人员划分&#xff1a;网页设计人员应用程序设计人员UI组件设计人员 所有与应用程序都由一个前端控制器(FacesServlet)来处理 2. JSF声明周期 FacesServlet充当用户和JSF应用程序之间的…

ztree项目

思路&#xff1a; 创建一个登陆 登陆上去 就是树 每个是的根节点有他所要展示的内容 表 可以有无数个 主要说的是创建树的表 这个是树的一个表 id 是 节点 name 名字 pid 根节点 url 路径 树的页面 后台通过登陆转的页面 转页面 在前台打印出你想要的数据 前台页面 退出 /*…

ztree使用

官方文档地址 http://www.treejs.cn/v3/main.php#_zTreeInfo 各种参数 http://www.treejs.cn/v3/api.php 简单静态调用 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><link href"https://cdn…

zTree 简介

zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。 zTree 是开源免费的软件&#xff08;MIT 许可证&#xff09;。如果您对 zTree 感兴趣或者愿意资助 zTree 继续发展下去&#xff0c;可以进行捐助。 zTree v3.0 …

ztree 详解

官网:http://www.treejs.cn/v3/demo.php#_101 里面有例子和demo,齐全。 zTree是一个基于jQuery的树形列表生成控件。 切换语言,点击下载,里面有各种demo: 里面各种demo,比博客写的好。 <!DOCTYPE html> <html lang="en"><head><meta ch…