JDBC(二)

来源:https://www.cnblogs.com/yif0118/archive/2020/01/25/12232721.html

1. PreparedStatement預編譯的語句對象 預編譯語句PreparedStatement 是java.sql中的一個介面,它是Statement的子介面。通過Statement對象執行SQL語句時,需要將SQL語句發送給DBMS,由 DBMS首先進行編譯後再執行。預編譯語句和State ...


1.   PreparedStatement預編譯的語句對象

預編譯語句PreparedStatement 是java.sql中的一個介面,它是Statement的子介面。通過Statement對象執行SQL語句時,需要將SQL語句發送給DBMS,由 DBMS首先進行編譯後再執行。預編譯語句和Statement不同,在創建PreparedStatement 對象時就指定了SQL語句,該語句立即發送給DBMS進行編譯。當該編譯語句被執行時,DBMS直接運行編譯後的SQL語句,而不需要像其他SQL語句那樣首先將其編譯,在執行

2.PreparedStatement和Statement的區別

在用法上不一樣:

①    Statement是普通的語句對象,PreparedStatement是預編譯的語句對象;

Statement創建對象時不傳入SQL,PreparedStatement創建對象是需要傳入SQL;

Statement在執行時需傳入SQL,PreparedStatement執行時不需傳入SQL。

②    Statement是拼接字元串效果,PreparedStatement不用拼接字元串;

③    PreparedStatement執行效率高於Statement;

④    PreparedStatement不是拼接字元串可以防止SQL註入問題;

具體實現代碼如下:

  1 package cn.yif.dao.impl;
  2 
  3 import cn.yif.domain.Student;
  4 import cn.yif.dao.IStudentDao;
  5 import cn.yif.domain.User;
  6 import cn.yif.utils.DBCPUtil;
  7 import cn.yif.utils.JDBCUtil;
  8 
  9 import java.sql.*;
 10 import java.util.ArrayList;
 11 import java.util.List;
 12 
 13 /**
 14  * @author Administrator
 15  * @create 2019-09-13-20:33
 16  */
 17 public class StudentDaoImpl implements IStudentDao {
 18     @Override
 19     public void insert(Student student) {
 20         Connection conn = null;
 21         PreparedStatement preStatement = null;
 22         try {
 23             //①載入(註冊)驅動,這部分硬編碼可以寫也可以不寫,jdbc4.0版本自帶了
 24             //Class.forName("com.mysql.jdbc.Driver");
 25             //②獲取連接
 26             //conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest01", "root", "admin");
 27             conn = JDBCUtil.getInstance().getConnection();
 28             //③預編譯的語句對象:提前編譯好SQL語句
 29             String insertSql = "insert into jdbcdemo02 (name, age) values (?, ?)";
 30             preStatement = conn.prepareStatement(insertSql);
 31             preStatement.setString(1, student.getName());
 32             preStatement.setInt(2, student.getAge());
 33             //④執行SQL語句:執行時無需代入SQL
 34             preStatement.execute();
 35         }catch (Exception ex){
 36             ex.printStackTrace();
 37         }finally {
 38             //⑤釋放資源
 39             JDBCUtil.getInstance().close(null, preStatement, conn);
 40         }
 41     }
 42 
 43     @Override
 44     public void update(Student student) {
 45         Connection conn = null;
 46         PreparedStatement preStatement = null;
 47         try {
 48             //①載入(註冊)驅動
 49             //Class.forName("com.mysql.jdbc.Driver");
 50             //②獲取連接
 51             //conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest01", "root", "admin");
 52             conn = JDBCUtil.getInstance().getConnection();
 53             //③預編譯的語句對象:提前編譯好SQL語句
 54             String updateSql = "update jdbcdemo02 set name = ?, age = ? where id = ?";
 55             preStatement = conn.prepareStatement(updateSql);
 56             preStatement.setString(1, student.getName());
 57             preStatement.setInt(2, student.getAge());
 58             preStatement.setInt(3, student.getId());
 59             //④執行SQL語句:執行時無需代入SQL
 60             preStatement.execute();
 61         }catch (Exception ex){
 62             ex.printStackTrace();
 63         }finally {
 64             //⑤釋放資源
 65             JDBCUtil.getInstance().close(null, preStatement, conn);
 66         }
 67     }
 68 
 69     @Override
 70     public void delete(Integer id) {
 71         Connection conn = null;
 72         PreparedStatement preStatement = null;
 73         try {
 74             //①載入(註冊)驅動
 75             //Class.forName("com.mysql.jdbc.Driver");
 76             //②獲取連接
 77             //conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest01", "root", "admin");
 78             conn = JDBCUtil.getInstance().getConnection();
 79             //③預編譯的語句對象:提前編譯好SQL語句
 80             String deleteSql = "delete from jdbcdemo02 where id = ?";
 81             preStatement = conn.prepareStatement(deleteSql);
 82             preStatement.setInt(1, id);
 83             //④執行SQL語句:執行時無需代入SQL
 84             preStatement.execute();
 85         }catch (Exception ex){
 86             ex.printStackTrace();
 87         }finally {
 88             //⑤釋放資源
 89             JDBCUtil.getInstance().close(null, preStatement, conn);
 90         }
 91     }
 92 
 93     @Override
 94     public Student queryOne(Integer id) {
 95         Connection conn = null;
 96         PreparedStatement preStatement = null;
 97         ResultSet resultSet = null;
 98         Student student = null;
 99         try {
100             //①載入(註冊)驅動
101             //Class.forName("com.mysql.jdbc.Driver");
102             //②獲取連接
103             //conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest01", "root", "admin");
104             conn = JDBCUtil.getInstance().getConnection();
105             //③預編譯的語句對象:提前編譯好SQL語句
106             String queryOneSql = "select * from jdbcdemo02 where id = ?";
107             preStatement = conn.prepareStatement(queryOneSql);
108             preStatement.setInt(1, id);
109             //④執行SQL語句:執行時無需代入SQL
110             resultSet = preStatement.executeQuery();
111             if(resultSet.next())
112             {
113                 student = new Student();
114                 student.setId(resultSet.getInt("id"));
115                 student.setName(resultSet.getString("name"));
116                 student.setAge(resultSet.getInt("age"));
117             }
118         }catch (Exception ex){
119 
120         }finally {
121             //⑤釋放資源
122             JDBCUtil.getInstance().close(resultSet, preStatement, conn);
123         }
124         return student;
125     }
126 
127     @Override
128     public List<Student> queryAll() {
129         Connection conn = null;
130         PreparedStatement preStatement = null;
131         ResultSet resultSet = null;
132         Student student = null;
133         List<Student> list = new ArrayList<Student>();
134         try {
135             //①載入(註冊)驅動
136             //Class.forName("com.mysql.jdbc.Driver");
137             //②獲取連接
138             //conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest01", "root", "admin");
139             conn = JDBCUtil.getInstance().getConnection();
140             //③獲取語句對象:用來執行SQL語句
141             String queryAllSql = "select * from jdbcdemo02";
142             preStatement = conn.prepareStatement(queryAllSql);
143             //④執行SQL語句
144             resultSet = preStatement.executeQuery(queryAllSql);
145             while (resultSet.next())
146             {
147                 student = new Student();
148                 student.setId(resultSet.getInt("id"));
149                 student.setName(resultSet.getString("name"));
150                 student.setAge(resultSet.getInt("age"));
151                 list.add(student);
152             }
153         }catch (Exception ex){
154             ex.printStackTrace();
155         }finally {
156             //⑤釋放資源
157             JDBCUtil.getInstance().close(resultSet, preStatement, conn);
158         }
159         return list;
160     }

 

3.登錄方式實現

這裡採用簡單模擬的方式,比較Statement與PreparedStatement的不同,以及SQL註入問題帶來的影響:

登錄實現代碼:

 1  @Override
 2     public User Login1_PreparedSt(String userName, String passWord) {
 3         Connection conn = null;
 4         PreparedStatement preStatement = null;
 5         ResultSet resultSet = null;
 6         User user = null;
 7         try {
 8             conn = JDBCUtil.getInstance().getConnection();
 9             String queryOneSql = "select * from jdbcdemo02_user where username = ? and password = ?";
10             preStatement = conn.prepareStatement(queryOneSql);
11             preStatement.setString(1, userName);
12             preStatement.setString(2, passWord);
13             resultSet = preStatement.executeQuery();
14             if(resultSet.next())
15             {
16                 user = new User();
17                 user.setId(resultSet.getInt("id"));
18                 user.setUsername(resultSet.getString("username"));
19                 user.setPassword(resultSet.getString("password"));
20                 user.setAge(resultSet.getInt("age"));
21                 user.setSex(resultSet.getInt("sex"));
22             }
23         }catch (Exception ex){
24 
25         }finally {
26             //⑤釋放資源
27             JDBCUtil.getInstance().close(resultSet, preStatement, conn);
28         }
29         return user;
30     }
31 
32     @Override
33     public User Login2_PreparedSt(String userName) {
34         Connection conn = null;
35         PreparedStatement preStatement = null;
36         ResultSet resultSet = null;
37         User user = null;
38         try {
39             conn = JDBCUtil.getInstance().getConnection();
40             String queryOneSql = "select * from jdbcdemo02_user where username = ?";
41             preStatement = conn.prepareStatement(queryOneSql);
42             preStatement.setString(1, userName);
43             resultSet = preStatement.executeQuery();
44             if(resultSet.next())
45             {
46                 user = new User();
47                 user.setId(resultSet.getInt("id"));
48                 user.setUsername(resultSet.getString("username"));
49                 user.setPassword(resultSet.getString("password"));
50                 user.setAge(resultSet.getInt("age"));
51                 user.setSex(resultSet.getInt("sex"));
52             }
53         }catch (Exception ex){
54 
55         }finally {
56             //⑤釋放資源
57             JDBCUtil.getInstance().close(resultSet, preStatement, conn);
58         }
59         return user;
60     }
61 
62     @Override
63     public User Login1_St(String userName, String passWord) {
64         Connection conn = null;
65         Statement statement = null;
66         ResultSet resultSet = null;
67         User user = null;
68         try {
69             conn = JDBCUtil.getInstance().getConnection();
70             statement = conn.createStatement();
71             String queryOneSql = "select * from jdbcdemo02_user where username = '"+userName+"' and password = '"+passWord+"'";
72             resultSet = statement.executeQuery(queryOneSql);
73             if(resultSet.next())
74             {
75                 user = new User();
76                 user.setId(resultSet.getInt("id"));
77                 user.setUsername(resultSet.getString("username"));
78                 user.setPassword(resultSet.getString("password"));
79                 user.setAge(resultSet.getInt("age"));
80                 user.setSex(resultSet.getInt("sex"));
81             }
82         }catch (Exception ex){
83 
84         }finally {
85             //⑤釋放資源
86             JDBCUtil.getInstance().close(resultSet, statement, conn);
87         }
88         return user;
89     }

 

後臺使用SQL註入測試代碼:

 1 @org.junit.Test
 2     public void Login1_PreparedSt() {
 3         User test1 = new User();
 4         //正常情況:未有SQL註入
 5         test1.setUsername("李華");
 6         test1.setPassword("123456");
 7         test1.setSex(2);
 8         //異常情況:有SQL註入
 9 //        test1.setUsername(" 'or 1=1 or' ");
10 //        test1.setPassword("456");
11 //        test1.setSex(2);
12         IStudentDao userDao = new StudentDaoImpl();
13         User user = userDao.Login1_PreparedSt(test1.getUsername(), test1.getPassword());
14         if(user != null){
15             System.out.println(String.format("恭喜%s登錄成功!", user.getUsername()));
16         }
17         else {
18             System.out.println("用戶名或密碼錯誤,登錄失敗!");
19         }
20     }
21 
22     @org.junit.Test
23     public void Login2_PreparedSt() {
24         User test1 = new User();
25         test1.setUsername("李華");
26         test1.setPassword("123456");
27         test1.setSex(2);
28         IStudentDao userDao = new StudentDaoImpl();
29         User user = userDao.Login2_PreparedSt(test1.getUsername());
30         if(user != null){
31             if(user.getPassword().equals(test1.getPassword())){
32                 System.out.println(String.format("恭喜%s登錄成功!", user.getUsername()));
33             }
34             else {
35                 System.out.println("密碼錯誤,登錄失敗!");
36             }
37         }
38         else {
39             System.out.println("用戶名錯誤,登錄失敗!");
40         }
41     }
42 
43     @org.junit.Test
44     public void Login1_St() {
45         User test1 = new User();
46         //正常情況:未有SQL註入
47         //test1.setUsername("李華");
48         //test1.setPassword("123456");
49         //test1.setSex(2);
50         //異常情況:有SQL註入
51         test1.setUsername(" 'or 1=1 or' ");
52         //這裡就是一條拼接的SQL -- select * from jdbcdemo02_user where username = ''or 1=1 or'' and password = 12344
53         test1.setPassword("145");
54         test1.setSex(2);
55         IStudentDao userDao = new StudentDaoImpl();
56         User user = userDao.Login1_St(test1.getUsername(), test1.getPassword());
57         if(user != null){
58             System.out.println(String.format("恭喜%s登錄成功!", user.getUsername()));
59         }
60         else {
61             System.out.println("用戶名或密碼錯誤,登錄失敗!");
62         }
63     }

 

4.連接池

4.1.連接池介紹

連接池:簡單地說,就是用來裝連接對象的容器。

背景:在高併發訪問的網頁上,每次請求都會創建一個connection,因此會非常浪費資源(記憶體),當同時1000人訪問的時候,那就會占用很多資源,因此浪費很多時間並且導致容器操作系統崩潰。

而連接池裡面取connection則只需要從連接池裡面拿到,不需要用戶名和密碼,用完之後,還回到連接池。

在Java中,在Java中,連接池使用javax.sql.DataSource介面來表示連接池. 這裡的DataSource就是連接池。連接池就是DataSource。DataSource是介面,和JDBC一樣,是Sun公司開發的一套介面,需要各大廠商去實現:導入各大廠商對應的jar包;

常用的DataSource的實現有下麵兩種方式:

  DBCP:  Spring推薦的(Spring框架已經集成DBCP)

  C3P0:  Hibernate推薦的(早期)(Hibernate框架已經集成C3P0)

 

DBCP連接池配置文件

dbcp.properties

#連接字元串

url=jdbc:mysql://localhost:3306/jdbcdemo

#用戶名

username=root

#密碼

password=admin

#驅動的類路徑

driverClassName=com.mysql.jdbc.Driver

#連接池啟動時的初始值

initialSize=1

#連接池的最大值

maxActive=50

#連接池的最大空閑數

maxIdle=20

具體代碼實現如下:

 1  @Override
 2     public Student queryOneByDBCP(Integer id) {
 3         Connection conn = null;
 4         PreparedStatement preStatement = null;
 5         ResultSet resultSet = null;
 6         Student student = null;
 7         try {
 8             //①載入(註冊)驅動
 9             //Class.forName("com.mysql.jdbc.Driver");
10             //②獲取連接
11             //conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest01", "root", "admin");
12             conn = DBCPUtil.getInstance().getConnection();
13             //③預編譯的語句對象:提前編譯好SQL語句
14             String queryOneSql = "select * from jdbcdemo02 where id = ?";
15             preStatement = conn.prepareStatement(queryOneSql);
16             preStatement.setInt(1, id);
17             //④執行SQL語句:執行時無需代入SQL
18             resultSet = preStatement.executeQuery();
19             if(resultSet.next())
20             {
21                 student = new Student();
22                 student.setId(resultSet.getInt("id"));
23                 student.setName(resultSet.getString("name"));
24                 student.setAge(resultSet.getInt("age"));
25             }
26         }catch (Exception ex){
27 
28         }finally {
29             //⑤釋放資源
30             DBCPUtil.getInstance().close(resultSet, preStatement, conn);
31         }
32         return student;
33     }

 

DBCPUtil.java文件:

 1 package cn.yif.utils;
 2 
 3 import org.apache.commons.dbcp.BasicDataSource;
 4 import org.apache.commons.dbcp.BasicDataSourceFactory;
 5 
 6 import javax.sql.DataSource;
 7 import java.io.IOException;
 8 import java.sql.*;
 9 import java.util.Properties;
10 
11 public class DBCPUtil {
12     //使用靜態static類構造單例模式
13     private DBCPUtil(){ }
14     //在靜態代碼塊中創建instance的實例,這裡使用static靜態變數來保存
15     private static DBCPUtil instance = null;
16     //每次都要載入驅動,這裡定義一個Properties,把資源文件裡面的內容讀到Properties裡面
17     private static Properties properties = null;
18     //定義一個連接池對象
19     //private static BasicDataSource ds = null;
20     private static DataSource ds = null;
21     //JDBCUtil類載入的時候,就載入註冊驅動
22     static {
23         properties = new Properties();
24         try {
25             //當前線程類載入器載入獲取properties文件
26             properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties"));
27             //方式一:創建一個BasicDataSource對象來讀取配置文件
28 //            ds = new BasicDataSource();
29 //            ds.setDriverClassName(properties.getProperty("driverClassName"));
30 //            ds.setUrl(properties.getProperty("url"));
31 //            ds.setUsername(properties.getProperty("username"));
32 //            ds.setPassword(properties.getProperty("password"));
33             //方式二:使用工廠DataSourceFactory來載入配置文件
34             try {
35                 ds = BasicDataSourceFactory.createDataSource(properties);
36             } catch (Exception e) {
37                 e.printStackTrace();
38             }
39         } catch (IOException e) {
40             e.printStackTrace();
41         }
42         instance = new DBCPUtil();
43     }
44 
45     public static DBCPUtil getInstance(){
46         return instance;
47     }
48 
49     //抽取獲取連接Connection的方法
50     public Connection getConnection() throws SQLException {
51         //這裡不再使用DriverManager,而應該使用BasicDataSource,從連接池中拿到這個連接
52         return ds.getConnection();
53     }
54 
55     //抽取JDBC關閉資源的close方法
56     public void close(ResultSet resultSet, Statement statement, Connection conn){
57         try {
58             if(resultSet != null){
59                 resultSet.close();
60             }
61         } catch (SQLException e) {
62             e.printStackTrace();
63         }
64         try {
65             if(statement != null){
66                 statement.close();
67             }
68         } catch (SQLException e) {
69             e.printStackTrace();
70         }
71         try {
72             if(conn != null){
73                 conn.close();
74             }
75         } catch (SQLException e) {
76             e.printStackTrace();
77         }
78     }
79 }

 


您的分享是我們最大的動力!

更多相關文章
  • 資料庫表關係設計也是常有場景,本章介紹如何設計一個實體關係圖 1:新建項目,在Model Explore中Add Diagram | ER Diagram到指定的元素中; 2:從Toolbox中創建Entity到ER Diagram畫布中; 雙擊視圖元素可以快速進行編輯,添加說明……,實體屬性在右側 ...
  • UML 類圖中的概念 類圖關係:泛化(繼承)、實現、聚合、組合、關聯、依賴 類圖的詳解可在網上查詢(推薦https://zhuanlan.zhihu.com/p/24576502) 它描述了在一個系統中的對象和他們的關係,能夠讓我們在正確編寫代碼以前對系統有一個全面的認識。一個單獨的類圖描述系統的一 ...
  • 本章內容參考官網即可,不做詳細說明,實踐出真知! starUMl規則主要是在模型設計的約束條件 https://docs.staruml.io/user-guide/validation-rules 快捷鍵 https://docs.staruml.io/user-guide/keyboard-sh ...
  • 這章比較簡單,主要是對視圖元素的樣式調整 主要是在視圖元素右下角設置,可以修改視圖元素的相關樣式 字體樣式 顏色 鏈接線樣式 對齊樣式 Stereotype Display-視圖元素的樣式屬性 菜單Format | Stereotype Display | [StereotypeDisplayKin ...
  • Diagrams(圖)可以理解為畫布 1:創建圖 在右側的Model Explorer管理界面的第一個節點右鍵,或者選擇菜單中Model | Add Diagram | [DiagramType]都可以創建 2:Delete Diagram 選擇後滑鼠右鍵或菜單Edit中 3:Open Diagra ...
  • 1:創建空的項目 創建項目可以按Ctrl+N或選擇菜單File| New,StarUML安裝打開後預設會有個空項目結構。 2:創建模板項目 可以通過選擇模板來啟動建模項目(會根據模板創建項目結構)。 要使用模板啟動項目,請從File| | New From TemplateName中選擇。 Star ...
  • 為什麼用StarUML UML建模工具比較常見的PowerDesigner ROSE StarUML starUML-開源免費(1-2百M),PowerDesigner-精細和一體化(6-7百M),ROSE-大而全(3-4百M) 看個人設計目的,starUML(http://staruml.io/) ...
  • 為什麼用UML 項目需要,在項目開發實現前期進行框架技術設計(條條大路通羅馬通羅馬,畫圖或者寫代碼都可以,適合就可以!)。 用戶的交互我們通常用Axure(原型設計)體現, 框架和功能結構設計則用UML體現,清楚自已使用目的,是否有用仁者見仁智者見智。 A:方便業務設計交流,理清思路,統一的規範描述 ...
一周排行
  • 介紹ASP.NET Core框架 在這篇文章中,我將要向你們簡短介紹一下ASP.NET Core 框架。當今社會,當提到軟體開發,每個人都是討論著開源以及跨平臺開發。總所周知,微軟是以它的基於Windows產品出名的,比如Windows系統,Office辦公套件等。現在我們處在新時代軟體開發的潮流中 ...
  • 在4月2日,發佈了.NET 5.0 Preview2,這次發佈對一些功能和性能做了相關的改進,同時後面也會實施5.0版本更多的功能,其中一些功能設計目前也在 "dotnet/designs" 中顯示,在 ".NET 5 Preview1" 中可以看到.NET 5里程碑中已經完成的建設任務,當然可以查 ...
  • 這篇文章中,我將教大家如何從頭到尾創建ASP.NET Core Web應用程式,這個系列,前面我已經寫了三篇文章,大家看這篇文章之前,可以先去熟悉一下前面的3篇文章,打一下基礎。在這篇文章中,我將和大家討論下麵兩個問題:使用Visual Studio 2019創建ASP.NET Core Web應用 ...
  • 前言 在上一篇中簡單介紹了Linq的入門級用法,這一篇嘗試講解一些更加深入的使用方法,與前一篇的結構不一樣的地方是,這一篇我會先介紹Linq里的支持方法,然後以實際需求為引導,分別以方法鏈的形式和類SQL的形式寫出來。 前置概念介紹 1. 謂詞、斷言,等價於 即返回bool的表達式 2. 表達式樹, ...
  • 在這篇文章中,我將詳細講解ASP.NET Core Project File.如果你還沒看我這個系列的前面幾篇文章,先去看看,打好基礎,再來看這篇吧。 如果你使用過之前版本的.NET Framework,你就會知道,當你使用C#創建應用程式的時候,.NET Framework框架將會創建尾碼名為”. ...
  • 前言 命名空間已經在 .NET 中使用了多年,一直追溯到 .NET Framework 1.1。它在 .NET 實施本身的數百個位置中使用,並且直接被成千上萬個應用程式使用。在所有這些方面,它也是 CPU 消耗的重要來源。 但是,從性能角度來看,正則表達式在這幾年間並沒有獲得太多關註。在 2006 ...
  • 2020年4月2日微軟.NET 團隊的項目經理 Richard 在博客上 發佈了.NET 5 Preview 2:https://devblogs.microsoft.com/dotnet/announcing-net-5-0-preview-2/ ,3月16號,Scott Hunter 在博客中發 ...
  • 為表達全國各族人民對抗擊新冠肺炎疫情鬥爭犧牲烈士和逝世同胞的深切哀悼,國務院今天發佈公告,決定2020年4月4日舉行全國性哀悼活動。 當使用控制項模板時,需要決定如何更廣泛地共用模板,以及是否希望自動地或明確地位用模板。 第一個問題是關於希望在何處使用模板的問題。例如,是將它們限制在特定視窗中嗎?大多 ...
  • 前言:在大一學習了C語言之後,基本掌握了一門面向過程的程式設計語言,本學期所學習的java是一門面向對象的語言,在問題的解決方面不像C一樣是以過程來思考問題,而是要以面向對象的思維來解決問題。此篇文章是對於本學期前三次Java作業的一個階段性總結,第一次作業花費了最多的時間,有一個測試點沒有過,第二 ...
  • 1. 2.創建頭文件選擇C/C++ Header file 3.源程式文件與頭文件不在一個地址話,需要在導入的時候寫清楚頭文件所在地址 例如名為giligli.h的頭文件 #include”地址giligli.h” 4. 如圖D包含了兩個a 重覆定義會產生錯誤。利用條件編譯可以很好的避免重覆定義 # ...