黑马程序员_反射

------- android培训java培训、期待与您交流! ----------

反射的经典解释:反射就是把Java类中的各种成分映射成相应的java类。

而且反射并不是JDK1.5的新特性,从JDK1.2开始就有了,在框架的开发中应用较多。

反射比较占用性能,反射会导致系统性能下降.

如何得到各个字节码对应的实例对象( Class类型)

类名.class,例如,System.class
对象.getClass(),例如,new Date().getClass()
Class.forName("类名"),例如,Class.forName("java.util.Date");

代码举例:
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");

Class类描述哪些信息:类的名字,类的访问属性,类所属于的包名,字段名称的列表、方法名称的列表等等

Class的实例对象代表内存里面的一份字节码

forName的作用:

如果已经加载过,呆在java虚拟机里面就直接取,如果java虚拟机里还没有这份字节码,则用类加载器去加载,把加载进来的字节码缓存在java虚拟机里面 ,以后要得到这份字节码就不用加载了。

Class cls = void.class;这样写是可以的

构造方法的反射:

Constructor类代表某个类中的一个构造方法

得到某个类所有的构造方法:
例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

代码举例:
Constructor constructor1 = String.class.getConstructor(StringBuffer.class/* 类型 */);
// 编译的时候不知道constructor1是String的构造方法,运行的时候才知道,所以要类型转换
String str = (String) constructor1.newInstance(new StringBuffer("abc")/* 同样类型的对象 */);
System.out.println(str.charAt(2));

得到某一个构造方法:
例子:   
Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

//获得方法时要用到类型
创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));

成员变量的反射:

Field类代表某个类中的一个成员变量

定义一个ReflectPoint类,属性:x和y

public class ReflectPoint {

private int x;
public int y;


public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}

ReflectPoint pt1 = new ReflectPoint(3, 5);
// fieldY 不是对象身上的变量而是类身上的变量,用它去取对象身上的值
Field fieldY = pt1.getClass().getField("y");
System.out.println(fieldY.get(pt1));

需要强调的是:fieldY不是对象上的变量,而是类身上的变量,通过它去获得某个对象身上变量的值。(即上面代码红色的部分)

由于x的访问属性为private,则通过这样的方式会报错。

// 暴力反射
Field fieldX = pt1.getClass().getDeclaredField("x");
fieldX.setAccessible(true);
System.out.println(fieldX.get(pt1));

例题:

作业:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。

定义ReflectPoint类:

public class ReflectPoint {

public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "love";



@Override
public String toString() {
return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ", str3="
+ str3 + "]";
}
}

在ReflectTest类中通过changeStringValue(Object obj)方法来改变值

调用:

changeStringValue(pt1);
System.out.println(pt1);

方法:

private static void changeStringValue(Object obj) throws Exception {


//通过对象的字节码得到对象的字段
Field[] fields = obj.getClass().getFields();
for (Field field : fields) {

//使用==进行判断字段的类型是否和字符串的字节码相同,注意这里用==要比equals好,因为字节码只有一份.
if (field.getType() == String.class) {
String oldValue = (String) field.get(obj);
String newValue = oldValue.replace('b', 'a');
field.set(obj, newValue);
}

方法的反射:

Str1 有 CharAt,str2也有charAt 方法,方法与对象无关,它是属于类的

Method类代表某个类中的一个成员方法

得到类中的某一个方法:
例子:
Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str, 1)); 

用反射的方式得到字节码里的方法

Method methodCharAt = String.class.getMethod("charAt"int.class);

System.out.println(methodCharAt.invoke(str1, 1));

面向对象形象解释:你给门发了个消息,门自己关上了

列车司机刹车,司机给列车发了个信号,列车自己停下了

把变量搞成私有的,如果谁要操作这个变量,那么这个变量在谁身上,这个方法就应该在谁身上

由于静态方法的调用不需要对象,所以methodCharAt.invoke(null, 1),这里为null

Jdk1.4和Jdk1.5的invoke方法的区别:
Jdk1.5:public Object invoke(Object obj,Object... args)
Jdk1.4:public Object invoke(Object obj,Object[] args),即按Jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。

用反射方式执行某个类中的main方法:

普通方式:

TestArguments.main(new String[]{"111","222","333"});

反射方式:
String startingClassName = args[0];
Method mainmethod = Class.forName(startingClassName).getMethod("main",String[].class);
//mainmethod.invoke(null,new Object[]{new String[]{"111","222","333"}});
mainmethod.invoke(null,(Object)new String[]{"111","222","333"});

每个数组的父类都是Object

mainmethod.invoke(null,(Object)new String[]{"111","222","333"});

跟编译器说这是一个对象,不要拆包。

数组的反射:

具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。

int [] a1 = new int[]{1,2,3};
int [] a2 = new int[4];
int [][] a3 = new int[2][3];
String [] a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass() == a2.getClass());
//System.out.println(a1.getClass() == a3.getClass());
//System.out.println(a1.getClass() == a4.getClass());
System.out.println(a1.getClass().getName());
System.out.println(a4.getClass().getName());
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a3.getClass().getSuperclass().getName());

Object aObj1 = a1;
Object aObj2 = a3;
Object aObj6 = a4;
//Object[] aObj3 = a1;
Object[] aObj4 = a3;
Object[] aObj5 = a4;

System.out.println(a1);
System.out.println(a4);

如果用反射,每一个数组都属于同一个class

对象得到字节码用方法,getClass()

System.out.println(a1.getClass().getName());

得到[I

[表示数组,I表示整数

数组的维数和类型相同得到的字节码是同一份

基本类型不是Object,所以

int [] a1 = new int[3];

Object[] aObj3 = a1;

这样不行,但是

Object aObj1 = a1;

Object aObj2 = a3;

Object aObj6 = a4;

Object[] aObj4 = a3;

Object[] aObj5 = a4;

都可以

int [] a1 = new int[3];

int [] a2 = new int[4];

int [][] a3 = new int[2][3];

String [] a4 = new String[3];

int [] a1 = new int[]{1,2,3};

int [] a2 = new int[4];

int [][] a3 = new int[2][3];

String [] a4 = new String[]{"a","b","c"};

赋值之后就不能加长度了

Arrays

System.out.println(Arrays.asList(a1));

System.out.println(Arrays.asList(a4));

结果:

[[I@1175422]

[a, b, c]

String 符合了jdk 1.4 的语法

asList

Public static List asList(Object[] a)

但是int不符合,基本类型不是Objectjdk 1.4 就交给1.5来处理识别成下面这样

asList

public static <T> List<T> asList(T... a)

就给当成了一个Object,而不是Object数组

反射的作用:实现框架功能:

因为在写才程序时无法知道要被调用的类名,所以在程序中无法直接new 某个类的实例对象了,而要用反射方式来做。

综合案例:

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;

public class ReflectTest2 {


public static void main(String[] args) throws Exception {

//一定要记住用完整的路径,但完整的路径不是硬编码而是运算出来的
//InputStream ips = new FileInputStream("config.properties");


//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("com/yy/day1/config.properties");

//相对路径,相对当前目录
//InputStream ips = ReflectTest2.class.getResourceAsStream("config.properties");
//绝对路径,不管相对还是绝对,他们内部都是调用ClassLoader
InputStream ips = ReflectTest2.class.getResourceAsStream("/com/yy/day1/config.properties");
Properties props = new Properties();
props.load(ips);
//不关可能会造成内存泄露,系统资源一直被占用,自己被干掉了,自己指向的操作系统的东西还在
ips.close();

String className = props.getProperty("className");
Collection collections = (Collection)Class.forName(className).newInstance(); 
//Collection collections = new HashSet();
//Collection collections = new ArrayList();
ReflectPoint pt1 = new ReflectPoint(3, 3);
ReflectPoint pt2= new ReflectPoint(5, 5);
ReflectPoint pt3 = new ReflectPoint(3, 3);

collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);

/**
 * 如果不改pt1.y = 7,取得的结果是1个,如果改了取得的结果是2个,这个就是内存泄露,因为一改,hashCode的值变了,去删的时候,不在原来的那个存储区域了,所以删不掉。
 */
//pt1.y = 7;
//collections.remove(pt1);
System.out.println(collections.size());
}
}



  -------  android培训java培训、期待与您交流! ----------  详细请查看: http://edu.csdn.net/heima/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 支持向量机非线性回归通用MATLAB程序解析 #### 一、概述 本文将详细介绍一个基于MATLAB的支持向量机(SVM)非线性回归的通用程序。该程序采用支持向量机方法来实现数据的非线性回归,并通过不同的核函数设置来适应不同类型的数据分布。此外,该程序还提供了数据预处理的方法,使得用户能够更加方便地应用此程序解决实际问题。 #### 二、核心功能与原理 ##### 1. 支持向量机(SVM) 支持向量机是一种监督学习模型,主要用于分类和回归分析。对于非线性回归任务,SVM通过引入核技巧(kernel trick)将原始低维空间中的非线性问题转换为高维空间中的线性问题,从而实现有效的非线性建模。 ##### 2. 核函数 核函数的选择直接影响到模型的性能。本程序内置了三种常用的核函数: - **线性核函数**:`K(x, y) = x'y` - **多项式核函数**:`K(x, y) = (x'y + 1)^d` - **径向基函数(RBF)**:`K(x, y) = exp(-γ|x - y|^2)` 其中RBF核函数被广泛应用于非线性问题中,因为它可以处理非常复杂的非线性关系。本程序默认使用的是RBF核函数,参数`D`用于控制高斯核函数的宽度。 ##### 3. 数据预处理 虽然程序本身没有直接涉及数据预处理的过程,但在实际应用中,对数据进行适当的预处理是非常重要的。常见的预处理步骤包括归一化、缺失值处理等。 ##### 4. 模型参数 - **Epsilon**: ε-insensitive loss function的ε值,控制回归带宽。 - **C**: 松弛变量的惩罚系数,控制模型复杂度与过拟合的风险之间的平衡。 #### 三、程序实现细节 ##### 1. 函数输入与输出 - **输入**: - `X`: 输入特征矩阵,维度为(n, l),其中n是特征数量,l是样本数量。 - `Y`: 目标值向量,长度为l。 - `Epsilon`: 回归带宽。 - `C`: 松弛变量的惩罚系数。 - `D`: RBF核函数的参数。 - **输出**: - `Alpha1`: 正的拉格朗日乘子向量。 - `Alpha2`: 负的拉格朗日乘子向量。 - `Alpha`: 拉格朗日乘子向量。 - `Flag`: 标记向量,表示每个样本的类型。 - `B`: 偏置项。 ##### 2. 核心代码解析 程序首先计算所有样本间的核矩阵`K`,然后构建二次规划问题并求解得到拉格朗日乘子向量。根据拉格朗日乘子的值确定支持向量,并计算偏置项`B`。 - **核矩阵计算**:采用RBF核函数,通过`exp(-(sum((xi-xj).^2)/D))`计算任意两个样本之间的相似度。 - **二次规划**:构建目标函数和约束条件,使用`quadprog`函数求解最小化问题。 - **支持向量识别**:根据拉格朗日乘子的大小判断每个样本是否为支持向量,并据此计算偏置项`B`。 #### 四、程序扩展与优化 - **多核函数支持**:可以通过增加更多的核函数选项,提高程序的灵活性。 - **自动调参**:实现参数自动选择的功能,例如通过交叉验证选择最优的`Epsilon`和`C`值。 - **并行计算**:利用MATLAB的并行计算工具箱加速计算过程,特别是当样本量很大时。 #### 五、应用场景 该程序适用于需要进行非线性回归预测的场景,如经济预测、天气预报等领域。通过调整核函数和参数,可以有效应对各种类型的非线性问题。 ### 总结 本程序提供了一个支持向量机非线性回归的完整实现框架,通过灵活的核函数设置和参数调整,能够有效地处理非线性问题。对于需要进行回归预测的应用场景,这是一个非常实用且强大的工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值