предисловие
Только лысая голова может стать сильнее.
Текст был включен в мою избранную статью на GitHub, Welcome Star.:GitHub.com/Zhongf UC очень…
Сегодня давайте кратко напишем отражение Java. Я не планировал писать о точке знания отражения, но многие читатели спрашивали меня: «Кажется, в вашей точке знания отсутствует отражение. Можете ли вы это компенсировать?»
В эти выходные тоже немного пусто, так что вот мое простое понимание отражения. Это ознакомительная статья, здесь нет продвинутых знаний, надеюсь, она может быть полезна новичкам. Если в статье что-то не так, пожалуйста, прокомментируйте это в области комментариев и укажите на это~
Я написал общие и важные моменты знаний в Java (Сейчас более 200 оригинальных технических статей), если вы хотите увидеть студентов, вы можете также обратить внимание на мойGitHubчтобы получить все мои оригинальные статьи.
1. Предисловие
Изучая основы Java, вы обычно изучаете рефлексию. Когда я впервые узнал об отражении, я не понимал, для чего оно используется. Изучил некоторые открытия API: "Очевидно, я могу напрямую создать новый объект, почему он должен ходить по кругу, сначала получать объект класса, а затем вызывать метод объекта класса для создания объекта, разве это не лишнее?"
Я полагаю, что у многих людей возникнет эта идея, когда они впервые изучают рефлексию (я не верю, что я один такой глупый!!)
А при поиске релевантной информации я обычно только объясняю серию API рефлексии, и всегда не понимаю, в чем польза рефлексии, об этом расскажет эта статья.Я чувствую себя хорошо, поставьте мне лайк
Во-вторых, вывести объект класса
Сначала давайте посмотрим на кусок кода:
public class Demo {
// 自建了一个Student类
class Student{
}
public static void main(String[] args) {
// 将Object 强转成Student类
Object o = new Object();
Student s = (Student) o;
}
}
Когда мы напишем этот кусок кода в IDE, ошибок не будет. Но когда мы выполним, мы будем знать навернякаПринудительный поворот не удался.
Итак, как «Java» (по сути, JVM) узнает, что мы написалисильный поворотЕсть какие-либо проблемы? может зависеть отClass
возражать против помощи в суждении.
Если вы читаете мое письмоJVM
Все учащиеся в статье должны знать процесс загрузки объекта. Если вы не читали ее, вы можете пойти и посмотреть ее еще раз. Кстати, я рассмотрю ее здесь для вас:
-
Один
.java
файлы прошли черезjavac
После успешной компиляции команды вы получите.class的文件
-
Когда мы выполняем операцию инициализации (это может быть новая, это может быть инициализация подкласса, родительский класс также инициализируется вместе, это может быть отражение... и т. д.), она будет
.class
файл череззагрузчик классовзагружен вjvm
середина -
будет
.class
Загрузчик файлов загружается в jvm и снова делитсянесколько шагов, который включаетЗагрузите, подключите и инициализируйте -
Среди них при загрузке он будет в куче JavaСоздайте объект класса java.lang.Class, этот объект класса представляетИнформация, связанная с классом.
Поскольку сказано, что объект класса представляет информацию, относящуюся к классу, это означает, что пока что-то есть в классе, я могу найти это в объекте класса. Откроем IDE и посмотрим методы внутри:
Так что мы можемОпределить реальный тип объекта по объекту Class.
3. Введение в рефлексию
На самом деле отражение вокругClass
объект иjava.lang.reflect
Библиотека классов для изучения, это разнообразие API
Как на скриншоте вышеMethod
/Field
/Constructor
Это вjava.lang.reflect
Под библиотекой классов именно потому, что изучение этих библиотек классов не составляет труда, поэтому я никогда не писал статью на размышление.
Я не говорю, что помню эти API, но эти руководства по API очень, очень, очень легко понять в Интернете. Приступая к работе, на самом деле почти то же самое, что освоить следующее:
- Знать несколько способов получить объекты класса
- Создавайте объекты с помощью объектов класса, получайте конструкторы, переменные-члены и методы.
- Измените значение переменных-членов и вызовите методы через отражающий API.
/*
下面是我初学反射时做的笔记,应该可以帮到大家,代码我就不贴了。(Java3y你值得关注)
*/
想要使用反射,我先要得到class文件对象,其实也就是得到Class类的对象
Class类主要API:
成员变量 - Field
成员方法 - Constructor
构造方法 - Method
获取class文件对象的方式:
1:Object类的getClass()方法
2:数据类型的静态属性class
3:Class类中的静态方法:public static Class ForName(String className)
--------------------------------
获取成员变量并使用
1: 获取Class对象
2:通过Class对象获取Constructor对象
3:Object obj = Constructor.newInstance()创建对象
4:Field field = Class.getField("指定变量名")获取单个成员变量对象
5:field.set(obj,"") 为obj对象的field字段赋值
如果需要访问私有或者默认修饰的成员变量
1:Class.getDeclaredField()获取该成员变量对象
2:setAccessible() 暴力访问
---------------------------------
通过反射调用成员方法
1:获取Class对象
2:通过Class对象获取Constructor对象
3:Constructor.newInstance()创建对象
4:通过Class对象获取Method对象 ------getMethod("方法名");
5: Method对象调用invoke方法实现功能
如果调用的是私有方法那么需要暴力访问
1: getDeclaredMethod()
2: setAccessiable();
Поверьте мне, зайдите на некоторое время в поисковую систему, и вы узнаете. API рефлексии несложно изучить. Большинство людей не понимают рефлексию, потому что не знают, на что она способна. Позвольте мне объяснить мое объяснение ниже.
4. Зачем нужна рефлексия
Когда я впервые изучал Java, мне лично казалось, что сложно понять, зачем нужна рефлексия, потому что без определенного количества кода было сложно понять, почему мне нужно ходить по кругу, чтобы заниматься рефлексией.
Теперь я думаю, что отражение используется по двум основным причинам:
- Повышение гибкости программы
- Защитите детали реализации, чтобы сделать ее более удобной для пользователей.
Я всегда подчеркивал в своих статьях, что прежде чем изучать определенную технологию, вы должны понять, почему вы хотите изучить эту технологию, поэтому в моих статьях обычно уходит много времени на объяснение почему.
Вот несколько примеров, которые помогут вам понять
4.1 Случай 1 (JDBC)
думаю все написалиjdbc
Код, вставляю небольшой кусочек, все пересматривают:
Class.forName("com.mysql.jdbc.Driver");
//获取与数据库连接的对象-Connetcion
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java3y", "root", "root");
//获取执行sql语句的statement对象
statement = connection.createStatement();
//执行sql语句,拿到结果集
resultSet = statement.executeQuery("SELECT * FROM users");
Почему он превратился в следующую форму?
//获取配置文件的读入流
InputStream inputStream = UtilsDemo.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(inputStream);
//获取配置文件的信息
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//加载驱动类
Class.forName(driver);
Причина проста,Люди не хотят изменять код. Пока есть изменения, я пишу это в конфигурации, разве это не ароматно? Если однажды мое имя пользователя, пароль, URL-адрес и даже база данных будут изменены, я могу сделать это, изменив конфигурацию.
Вам вообще не нужно трогать мой код, просто измените конфигурацию, и все готово., что обеспечивает гибкость программы.
Некоторые люди могут спросить: «Это еще нужно изменить, я могу изменить код очень быстро, вы не хотите изменить конфигурацию?»
На самом деле это не одно и то же, приведу пример:
- Санваи написал компонент JDBC и записал в код различные конфигурации, такие как драйвер/имя пользователя/номер подключения к базе данных выше. Теперь, когда трое мошенников уволились, они собираются сбежать.
- Ao Bing пришел взять на себя код Sanwei.Ao Bing только начал заниматься проектом, и компания заявила, что изменит базу данных. Ао Бин сказал лидеру: «Я могу изменить конфигурацию этой штуки, и это будет сделано через несколько минут».
- Ао Бинг долго искал и не мог найти место для его настройки.Поскольку код, написанный Санцзяо, был вонючим и гнилым, поиск входа и соответствующей локации занял много времени.
Риск изменения кода больше, чем изменение конфигурации.Даже если вы не знаете реализации кодаВсе можно сделать, изменив конфигурацию.
Этоможно настроить через, что, вероятно, выполняется внутри путем отражения.
Это просто сказать, что это возможно, но не совсем. Некоторые настраиваемые параметры могут быть просто конфигурацией и не иметь ничего общего с отражением. Но в приведенном выше примере с jdbc драйвер загружается через отражение.
4.2 Случай 2 (SpringMVC)
Я считаю, что все изучили Servlet до изучения SpringMVC.Если вы не изучили его, рекомендуется прочитать мою статью и просмотреть ее.
Когда я изучал фреймворк MVC, больше всего меня поразило то, что мне нужны были различныеgetParameter()
, теперь пока соглашениеJavaBean
имя поля, вы можете заполнить значение.
Давайте перейдем к коду, это статус-кво изучения сервлета в то время:
//通过html的name属性,获取到值
String username = request.getParameter("username");
String password = request.getParameter("password");
String gender = request.getParameter("gender");
//复选框和下拉框有多个值,获取到多个值
String[] hobbies = request.getParameterValues("hobbies");
String[] address = request.getParameterValues("address");
//获取到文本域的值
String description = request.getParameter("textarea");
//得到隐藏域的值
String hiddenValue = request.getParameter("aaa");
Что произошло, когда мы изучили SpringMVC:
@RequestMapping(value = "/save")
@ResponseBody
public String taskSave(PushConfig pushConfig) {
// 直接使用
String name= pushConfig.getName();
}
Почему SpringMVC может это сделать? Фактически, черезотражениесделать.
Я полагаю, вы также испытали:
- Если имя атрибута вашего JavaBean несовместимо с переданным именем параметра, то "автоматическая сборка" завершается ошибкой. Поскольку отражение может найти имя поля только на основе имени параметра, если оно несовместимо, оно должно быть
set
Не входит. Итак, сборка не удалась.
Если мы используем фреймворк, почему мы часто пишем JavaBean и сохраняем имя поля и имя параметра одинаковыми, чтобы мы могли «автоматически» получить соответствующее значение. В этом преимущество размышлений.
Защитите детали реализации, чтобы сделать ее более удобной для пользователей.
5. Пишем ли мы много кода для отражения?
Большинство программистов пишут бизнес-код, и большинство программистов поддерживают старую систему На самом деле не так уж часто нам приходится писать код отражения самостоятельно.
Как видно из вышеизложенного, когда будет написан рефлексия? пишем самиКомпоненты/фреймворкикогда. Если вы хотите найти место для тренировки своих рефлексов, я думаюпользовательская аннотацияхороший выбор.
Поскольку сейчас во многих местах используются аннотации, главная причина в том, что они ясны и просты (больше не нужно сталкиваться с кучей XML-файлов, хахахаха~).
Я написал абзац, когда был новичком, вы можете просто сослаться на него, идеи похожи. Ниже приведен эффект использования (использование пользовательских аннотаций для добавления разрешений к различным интерфейсам)
@permission("添加分类")
/*添加分类*/ void addCategory(Category category);
/*查找分类*/
void findCategory(String id);
@permission("查找分类")
/*查看分类*/ List<Category> getAllCategory();
вернутьиграет рольОбъект службы для обработки пользовательских аннотаций:
public class ServiceDaoFactory {
private static final ServiceDaoFactory factory = new ServiceDaoFactory();
private ServiceDaoFactory() {
}
public static ServiceDaoFactory getInstance() {
return factory;
}
//需要判断该用户是否有权限
public <T> T createDao(String className, Class<T> clazz, final User user) {
System.out.println("添加分类进来了!");
try {
//得到该类的类型
final T t = (T) Class.forName(className).newInstance();
//返回一个动态代理对象出去
return (T) Proxy.newProxyInstance(ServiceDaoFactory.class.getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, PrivilegeException {
//判断用户调用的是什么方法
String methodName = method.getName();
System.out.println(methodName);
//得到用户调用的真实方法,注意参数!!!
Method method1 = t.getClass().getMethod(methodName,method.getParameterTypes());
//查看方法上有没有注解
permission permis = method1.getAnnotation(permission.class);
//如果注解为空,那么表示该方法并不需要权限,直接调用方法即可
if (permis == null) {
return method.invoke(t, args);
}
//如果注解不为空,得到注解上的权限
String privilege = permis.value();
//设置权限【后面通过它来判断用户的权限有没有自己】
Privilege p = new Privilege();
p.setName(privilege);
//到这里的时候,已经是需要权限了,那么判断用户是否登陆了
if (user == null) {
//这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。
throw new PrivilegeException("对不起请先登陆");
}
//执行到这里用户已经登陆了,判断用户有没有权限
Method m = t.getClass().getMethod("findUserPrivilege", String.class);
List<Privilege> list = (List<Privilege>) m.invoke(t, user.getId());
//看下权限集合中有没有包含方法需要的权限。使用contains方法,在Privilege对象中需要重写hashCode和equals()
if (!list.contains(p)) {
//这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。
throw new PrivilegeException("您没有权限,请联系管理员!");
}
//执行到这里的时候,已经有权限了,所以可以放行了
return method.invoke(t, args);
}
});
} catch (Exception e) {
new RuntimeException(e);
}
return null;
}
}
Наконец
Это размышление не совпадает со статьей в Интернете. Размышление в Интернете обычно знакомит с тем, как использовать API отражения. Если вы думаете, что это хорошо, дайте мне лайк 👍. Студенты, которые хотят увидеть другие точки знаний, вы можете оставить мне сообщение, я могу рассмотреть возможность его написания по мере необходимости (хахахаха, вдруг станет громким именем)
Другие точки знаний, связанные с этой статьей: процесс загрузки класса JVM, аннотации, динамический прокси, SpringMVC, JDBC Я уже написал статьи, студенты, которые хотят читать, могут подписаться на меня.GitHubПросто найдите релевантные ключевые слова.
если ты хочешьв реальном времениЕсли вы обратите внимание на мои обновленные статьи и галантерейные товары, которыми я делюсь, вы можете подписаться на мой публичный аккаунт "Java3y".
- 🔥Java красивая карта мозга
- 🔥Маршрут обучения Java
- 🔥Разработка общих инструментов
Ответить под публичным аккаунтом"888», чтобы получить его! !
Эта книга была включена в мои избранные статьи на GitHub, добро пожаловать, звезда:GitHub.com/Zhongf UC очень…
попросить лайк Пожалуйста, следите за ️ поделитесь пожалуйста 👥 Спросите сообщение 💬верно для меняочень полезно! ! !