1. 반사 메커니즘은 무엇입니까?
간단히 말해서, 반사 메커니즘은 프로그램이 실행되는 동안 자체 정보를 얻을 수 있음을 의미합니다. Java에서는 클래스 이름만 제공되면 리플렉션 메커니즘을 통해 클래스에 대한 모든 정보를 얻을 수 있습니다.
2. 반사 메커니즘은 어디에 사용됩니까?
때때로 우리는 약간의 지식을 사용했지만 전문 용어가 무엇인지 알지 못합니다. 방금 jdbc를 배웠을 때 Class.forName("com.mysql.jdbc.Driver.class")라는 코드 줄을 사용했습니다. newInstance() ; 하지만 그 당시에는 해당 코드 줄이 드라이버 개체 인스턴스를 생성했다는 것만 알았고 그 구체적인 의미는 몰랐습니다. 리플렉션 메커니즘에 대한 강의를 듣고 나서 이것이 리플렉션이라는 것을 깨달았습니다. 요즘에는 많은 오픈 프레임워크가 리플렉션 메커니즘을 사용하여 구현됩니다.
3. 반사 메커니즘의 장점과 단점
반사 메커니즘을 사용하는 이유는 무엇입니까? 객체를 직접 생성하는 것만으로는 충분하지 않나요? 여기에는 동적 및 정적 개념이 포함됩니다.
정적 컴파일: 유형은 컴파일 타임에 결정되고 개체는 바인딩됩니다. 즉, 전달됩니다.
동적 컴파일: 유형을 결정하고 런타임에 객체를 바인딩합니다. 동적 컴파일은 Java의 유연성을 극대화하고 다형성 애플리케이션을 구현하며 클래스 간의 결합을 줄입니다.
한마디로, 리플렉션 메커니즘의 장점은 객체를 동적으로 생성하고 컴파일할 수 있다는 점인데, 이는 특히 J2EE 개발에서 그 유연성이 매우 분명합니다. 예를 들어, 대규모 소프트웨어의 경우 한 번에 완벽하게 설계하는 것은 불가능합니다. 프로그램이 컴파일되고 출시된 후 특정 기능을 업데이트해야 한다고 판단되면 사용자에게 이전 버전을 제거하도록 요청할 수 없습니다. 새 버전을 다시 설치하면 이 소프트웨어는 확실히 많은 사람들이 사용하지 않을 것입니다. 정적이라면 기능 업데이트를 구현하기 위해 전체 프로그램을 한 번 다시 컴파일해야 하며, 리플렉션 메커니즘을 사용하는 경우에는 기능을 구현하기 위해 런타임에 동적으로 생성하고 컴파일하기만 하면 됩니다.
단점은 성능에 영향을 미친다는 것입니다. 리플렉션을 사용하는 것은 기본적으로 우리가 수행하려는 작업을 JVM에 알리고 요구 사항을 충족할 수 있는 해석된 작업입니다. 이러한 작업은 동일한 작업을 직접 수행하는 것보다 항상 느립니다.
4. 반사 메커니즘을 사용하여 어떤 정보를 얻을 수 있습니까?
한마디로, 클래스에 있는 모든 정보를 얻을 수 있지만 전제 조건은 클래스의 이름을 아는 것입니다. 그렇지 않으면 더 이상의 정보가 없습니다. 먼저 클래스의 전체 이름을 기반으로 클래스 객체를 생성해야 합니다. 들어오는 수업.
Class c=Class.forName("className"); 참고: className은 전체 이름이어야 합니다. 즉, cn.netjava.pojo.UserInfo와 같이 패키지 이름을 포함해야 합니다.
Object obj=c.newInstance();//객체의 인스턴스 생성
좋습니다. 객체가 있으면 모든 것을 쉽게 처리할 수 있습니다.
생성자를 얻는 방법
생성자 getConstructor(Class[] params)//지정된 매개변수에 따라 공용 생성자를 가져옵니다.
Constructor[] getConstructors()//모든 공개 생성자를 가져옵니다.
생성자 getDeclaredConstructor(Class[] params)//지정된 매개변수를 기반으로 공개 및 비공개 생성자를 가져옵니다.
Constructor[] getDeclaredConstructors()//모든 공개 생성자를 가져옵니다.
클래스 메서드의 메서드 가져오기
메소드 getMethod(String name, Class[] params), 메소드 이름 및 매개변수 유형을 기반으로 메소드를 가져옵니다.
Method[] getMethods()//모든 공개 메소드 가져오기
메소드 getDeclaredMethod(String name, Class[] params)//메소드 이름 및 매개변수 유형에 따라 공개 및 비공개 메소드를 얻습니다.
Method[] getDeclaredMethods()//모든 공개 및 비공개 메소드 가져오기
클래스에서 속성을 얻는 방법
Field getField(String name)//변수 이름에 따라 해당 공용 변수를 가져옵니다.
Field[] getFields()//클래스의 모든 공개 메소드를 가져옵니다.
필드 getDeclaredField(문자열 이름)//메서드 이름을 기반으로 공개 및 비공개 변수 가져오기
Field[] getDeclaredFields()//클래스의 모든 공개 및 비공개 메소드를 가져옵니다.
이것들은 일반적으로 사용되는 것들입니다. 이것만 알면 나머지는 모두 쉽게 처리할 수 있습니다.
5. 반사 메커니즘으로 무엇을 할 수 있나요?
처음 jdbc를 사용하기 시작했을 때 데이터베이스에 접근하기 위해 작성을 하면 토할 것 같은 느낌이 들었습니다. 테이블이 8개 있었는데, 각 테이블마다 추가, 삭제, 수정, 검색 작업이 있었습니다. 그 당시에는 개념도 몰랐습니다. 리플렉션 메커니즘을 사용하여 테이블에 다양한 DAO 클래스 생성에 대해 썼는데, 이는 개발 속도를 높일 뿐만 아니라 코드를 중복하게 만듭니다. 가장 끔찍한 점은 거의 동일해 보이고 직접 복사하고 수정한다는 것입니다. 여러 가지 낮은 수준의 실수(대문자와 소문자, 하나 이상 또는 문자 하나가 누락됨...)를 저지르기 쉽기 때문에 하나의 실수를 찾는 데 오랜 시간이 걸릴 수 있습니다.
Java 리플렉션 메커니즘을 사용하면 모든 것이 쉽게 처리됩니다. 추가, 삭제, 수정, 쿼리의 네 가지 메서드를 사용하여 dao 클래스를 작성하고 다른 개체를 전달할 필요가 없습니다. 각 테이블에 대한 dao 클래스를 사용하면 반사 메커니즘이 자동으로 나머지 작업을 수행하므로 이점이 있습니다. 직설적으로 말하면, 반사 메커니즘은 반복적이고 규칙적인 작업을 수행하는 데 도움이 되도록 설계되었으므로 자동으로 코드를 생성하는 많은 소프트웨어는 이제 규칙에 따라 관련 매개변수를 입력하기만 하면 반사 메커니즘을 사용하여 코드를 완성합니다. 레벨 프로그래머는 느리다. 느린 프로그래머는 사라졌다. 왜? 코드를 작성할 필요가 없기 때문에 누구나 개발할 수 있는데 프로그래머는 왜 하는 걸까요? 그래서 우리에게 남은 길은 단 하나, 열심히 일하고 더 열심히 일하고, 수석 프로그래머가 되어, 멍청한 소프트웨어 개발을 전문으로 하고, 다른 프로그래머들은 제쳐두고 식어가도록 두는 것입니다. 하하~
6. 데이터베이스 데이터 추가 및 확인을 위한 반영 메커니즘 활용 예시
기본 원칙: 데이터를 저장할 때 저장해야 하는 객체의 속성값을 모두 꺼낸 후 쿼리용 SQL문을 모아 쿼리된 데이터를 모두 자바 객체로 패키징한다.
게임의 규칙: 규칙 없이는 아무것도 없습니다. 특히 프로그램의 경우 규칙 없이는 할 수 없습니다.
1) 데이터베이스의 각 테이블 개체에는 pojo 클래스가 있고 테이블의 각 필드는 pojo 클래스의 속성에 해당합니다. 또한 pojo 클래스의 이름은 테이블 이름과 동일하며, 속성 이름과 필드 이름은 데이터베이스가 일반적으로 대소문자를 구분하지 않으므로 대소문자는 중요하지 않습니다.
2) pojo 클래스의 각 속성에 대한 표준 세트 및 가져오기 메소드를 추가합니다.
게임의 규칙에 따라 게임을 시작하겠습니다.
1. 먼저 데이터베이스에 테이블이 있습니다. 데이터베이스 이름이 blogsystem이고 테이블 이름이 userinfo라고 가정합니다. 그림과 같이:
2. 해당 pojo 클래스를 생성합니다.
다음과 같이 코드 코드를 복사합니다 .
패키지 cn.netjava.pojo;
공개 클래스 UserInfo {
개인 정수 ID;
개인 문자열 이름;
개인 문자열 비밀번호;
비공개 연령;
@보수
공개 문자열 toString() {
return "UserInfo [id=" + id + ", name=" + 이름 + ", pwd=" + pwd + ", age="
+ 나이 + "]";
}
공개 int getId() {
반환 ID;
}
공개 무효 setId(int id) {
this.id = 아이디;
}
공개 문자열 getName() {
이름 반환;
}
public void setName(문자열 이름) {
this.name = 이름;
}
공개 문자열 getPwd() {
비밀번호를 반환합니다.
}
공공 무효 setPwd(문자열 비밀번호) {
this.pwd = 비밀번호;
}
공개 int getAge() {
복귀 연령;
}
공개 무효 setAge(int age) {
this.나이 = 나이;
}
}
2. 데이터베이스 연결을 얻기 위한 팩토리 클래스를 작성합니다.
다음과 같이 코드 코드를 복사합니다 .
패키지 cn.netjava.factory;
import java.sql.Connection;
java.sql.DriverManager 가져오기;
공개 클래스 Connect2DBFactory {
공개 정적 연결 getDBConnection() {
연결 연결 = null;
노력하다 {
Class.forName("com.mysql.jdbc.Driver");
문자열 url = "jdbc:mysql://localhost:3306/blogsystem";
문자열 사용자 = "루트";
문자열 비밀번호 = "netjava";
conn = DriverManager.getConnection(url, 사용자, 비밀번호);
} 잡기(예외 e) {
e.printStackTrace();
}
반환 연결;
}
}
3. 데이터베이스를 운영하는 dao 클래스를 작성하는 것부터 재미가 시작됩니다.
다음과 같이 코드 코드를 복사합니다 .
패키지 cn.netjava.session;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
java.util.List 가져오기;
수입 cn.netjava.factory.Connect2DBFactory;
cn.netjava.pojo.UserInfo 가져오기;
공개 클래스 NetJavaSession {
/**
* 객체를 저장하는 SQL 문을 구문 분석합니다.
*
* @param 객체
*: 저장이 필요한 객체
* @return: 객체를 저장하는 SQL 문
*/
공개 정적 문자열 getSaveObjectSql(객체 개체) {
//SQL 문자열 정의
문자열 sql = ""에 삽입;
//객체의 클래스를 가져옵니다.
클래스 c = object.getClass();
//객체의 모든 메소드를 가져옵니다.
Method[] 메소드 = c.getMethods();
// 객체의 모든 속성을 가져옵니다.
Field[] 필드 = c.getFields();
// 객체 클래스의 이름을 가져옵니다.
문자열 cName = c.getName();
// 클래스 이름에서 테이블 이름을 구문 분석합니다.
문자열 tableName = cName.substring(cName.lastIndexOf(".") + 1,
cName.length());
sql += 테이블명 + "(";
List<String> mList = new ArrayList<String>();
List vList = new ArrayList();
for(메서드 method : 메소드) {
문자열 mName = method.getName();
if (mName.startsWith("get") && !mName.startsWith("getClass")) {
String fieldName = mName.substring(3, mName.length());
MList.add(필드명);
System.out.println("필드 이름------>" + fieldName);
노력하다 {
객체 값 = method.invoke(object, null);
System.out.println("실행 메서드에서 반환된 값: " + value);
if (문자열 값 인스턴스) {
vList.add("/"" + 값 + "/"");
System.out.println("필드 값------>" + value);
} 또 다른 {
vList.add(값);
}
} 잡기(예외 e) {
e.printStackTrace();
}
}
}
for (int i = 0; i < mList.size(); i++) {
if (i < mList.size() - 1) {
sql += MList.get(i) + ",";
} 또 다른 {
sql += MList.get(i) + ") 값(";
}
}
for (int i = 0; i < vList.size(); i++) {
if (i < vList.size() - 1) {
sql += vList.get(i) + ",";
} 또 다른 {
sql += vList.get(i) + ")";
}
}
SQL을 반환;
}
공개 정적 목록 getDatasFromDB(String tableName, int Id) {
null을 반환;
}
/**
* 개체를 데이터베이스에 저장
*
* @param 객체
*: 저장이 필요한 객체
* @return: 메소드 실행 결과, 1: 성공을 나타냄, 0: 실패를 나타냄
*/
공개 int saveObject(객체 객체) {
연결 con = Connect2DBFactory.getDBConnection();
문자열 sql = getSaveObjectSql(객체);
노력하다 {
// 문장 문장=(Statement) con.createStatement();
ReadyStatement psmt = con.prepareStatement(sql);
psmt.executeUpdate();
1을 반환합니다.
} 잡기(SQLException e) {
e.printStackTrace();
0을 반환합니다.
}
}
/**
* 데이터베이스에서 객체 가져오기
*
* @param arg0
*: 객체가 속한 클래스
* @param 아이디
*: 객체의 ID
* @return : 찾을 객체
*/
공용 개체 getObject(String className, int Id) {
// 테이블 이름을 알아낸다
문자열 tableName = className.substring(className.lastIndexOf(".") + 1,
className.length());
//클래스 이름을 기반으로 클래스 객체 생성
클래스 c = null;
노력하다 {
c = Class.forName(클래스이름);
} 잡기(ClassNotFoundException e1) {
e1.printStackTrace();
}
// 쿼리 SQL 문을 하나로 묶습니다.
문자열 sql = "select * from " + tableName + " where Id=" + Id;
System.out.println("SQL 문 찾기: " + sql);
// 데이터베이스 링크 가져오기
연결 con = Connect2DBFactory.getDBConnection();
//클래스의 인스턴스 생성
객체 obj = null;
노력하다 {
명령문 stm = con.createStatement();
// 검색문을 실행하여 반환된 결과 집합을 가져옵니다.
ResultSet 집합 = stm.executeQuery(sql);
// 객체의 메서드 배열을 가져옵니다.
Method[] 메소드 = c.getMethods();
// 결과 집합을 탐색합니다.
동안(set.next()) {
obj = c.newInstance();
//객체를 순회하는 방법
for(메서드 method : 메소드) {
문자열 methodName = method.getName();
// 객체의 메소드가 set으로 시작하는 경우
if (methodName.startsWith("set")) {
// 메소드 이름을 기반으로 데이터 테이블의 필드 이름을 가져옵니다.
문자열 열이름 = methodName.substring(3,
methodName.length());
// 메소드의 매개변수 유형을 가져옵니다.
Class[] parmts = method.getParameterTypes();
if (parmts[0] == String.class) {
// 파라미터가 String 타입인 경우 컬럼명에 따라 결과셋에서 해당 값을 얻어 set 메소드를 실행한다.
method.invoke(obj, set.getString(columnName));
}
if (parmts[0] == int.class) {
method.invoke(obj, set.getInt(columnName));
}
}
}
}
} 잡기(예외 e) {
e.printStackTrace();
}
반환 객체;
}
}
4. 테스트 시작의 효과는 어떻습니까?
다음과 같이 코드 코드를 복사합니다 .
패키지 cn.netjava.tester;
cn.netjava.pojo.UserInfo 가져오기;
cn.netjava.session.NetJavaSession 가져오기;
공개 클래스 테스터 {
공개 정적 무효 메인(문자열 인수[]) {
//NetJavaSession 객체를 가져옵니다.
NetJavaSession 세션 = new NetJavaSession();
//UserInfo 객체 생성
UserInfo 사용자 = 새로운 UserInfo();
//객체의 속성을 설정합니다.
user.setId(6988);
user.setAge(44);
user.setPwd("비밀번호");
user.setName("챔피언");
//객체를 데이터베이스에 저장
문자열 sql = session.getSaveObjectSql(user);
System.out.println("객체를 저장하는 SQL문: " + sql);
//객체 찾기
UserInfo userInfo = (UserInfo) session.getObject(
"cn.netjava.pojo.UserInfo", 6988);
System.out.println("얻은 정보: " + userInfo);
}
}
5. 인쇄된 결과:
7. 요약하자면
일반적으로 Java 리플렉션 메커니즘은 매우 유연하기 때문에 많은 문제를 해결할 수 있습니다. 이를 사용하면 데이터베이스 코드를 사용하는 대신 작업에 너무 많은 시간을 소비할 필요가 없습니다. 이 방법은 프로젝트의 논리적 기능에 더 많은 시간을 소비하므로 개발 시간이 크게 단축되고 코드 읽기가 쉬워집니다. 기존의 많은 오픈 소스 프레임워크는 리플렉션 메커니즘을 사용하여 파일을 구성한 다음 규칙에 따라 해당 메서드를 호출하기만 하면 됩니다.