getConstructor报错

package lius.day05;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class reflexed {
    public static void main(String[] args) {
        try{
            Class<?> clz = Class.forName("lius.day05.apple");   //clz可指向任意类型,?是通配符
            Method method = clz.getMethod("change", int.class);    //获取已经加载的类的方法
            Constructor constructor = clz.getConstructor(int.class);    //获取已经加载的类的构造器
            Object object = constructor.newInstance(7);    //通过刚刚获得的构造器来生成实例
            method.invoke(object,4);     //将刚刚生成的实例和参数传入method.invoke中,method代表了apple类里面的change(int b)方法
        }catch(ClassNotFoundException e){
            System.out.println("class not found");
        }catch(NoSuchMethodException | IllegalAccessException |InvocationTargetException | InstantiationException e){
            e.printStackTrace();
        }
    }

}
class apple{
    private int an = 10;
    public apple(int a)
    {
        an = a;
        System.out.println("apple has been build as:" + a);
    }


    static  //类的静态加载器,只要类被加载就会跑
    {
        System.out.println("this is a static class loader");
    }
    public void change(int b)
    {
        an = b;
        System.out.println("apple has been change as:" + b);
    }
}

当没有默认构造函数时

getConstructor()   //error

需要传进去一个int,因为如果没有参数,就无法构造出一个实例

Constructor constructor = clz.getConstructor(int.class);
Object object = constructor.newInstance(7);    //正确<br>
package lius.day05;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyDynamic implements InvocationHandler {
    private Object object;      //使用了通用的ProxyDynamic类包装HumanImply实例
    public ProxyDynamic(Object target)
    {
        this.object = target;
    }
    public Object invoke(Object obj, Method method,Object[] args) throws Throwable
    {
        if(method.getName().equals("eat"))
            before();   //加入业务逻辑
        Object res = method.invoke(object,args);    //也可以手动new一个目标对象传进去,在这个方法中调用了被代理对象的方法
        if(method.getName().equals("eat"))
            after();
        return res;
    }
    private void before()
    {
        System.out.println("cook");
    }
    private void after()
    {
        System.out.println("cleaning");
    }

    public static void main(String[] args) {
        Human human = new HumanImply();     //Human接口的实现
        ProxyDynamic dynamic = new ProxyDynamic(human);     //动态代理器的实例,这里这个动态代理可以代理任何类,内部有有invoke方法,实现了InvocationHandler接口

        System.out.println("=========================hand=======================");

        try {
            Object[] argsD = new Object[1];
            argsD[0] = new String("shit");
            dynamic.invoke(human.getClass(),human.getClass().getMethod("eat", String.class),argsD);
        }catch (Throwable e){
            e.printStackTrace();
        }

        System.out.println("=========================auto=======================");

        //loader:用哪个类加载器去加载代理对象
        //interface:动态代理类需要实现的接口
        //InvocationHandler h:动态代理方法在执行时,会调用h里面的invoke方法去执行
        //InvocationHandler是个接口,需要实现
        //Proxy.newProxyInstance可以理解为一个打包器,new ProxyDynamic(human)是生成代理(人),new HumanImply()是生成被代理(人),而下面这个是将两者绑在一起,生成一个目标对象
        //这个目标对象已经被代理了
        Human HumanProxy = (Human) Proxy.newProxyInstance(human.getClass().getClassLoader(),human.getClass().getInterfaces(),dynamic);   //实例化了一个具体的代理类(代理对象)
        HumanProxy.eat("apple");
        HumanProxy.walk(2);
        //将被代理的对象作为参数传入就可以执行里面的任意方法,所有的方法调用都通过invoke来完成。不用对每个方法进行处理

        System.out.println("=========================other=======================");


    }
}

手写regression

import numpy as np
def L1_Regression(data,alpha,lamda):
    n = len(data[0]) - 1
    theta = np.zeros(n)
    for times in range(100)
        for d in data:      #相当于 theta - alpha * Σ(hXi - Yi)  
            x = d[:-1]
            y = d[-1]
            g = np.dot(theta,x) - y # hXi - Yi
            theta = theta - alpha * g * x + lamda * theta   #正则化项 lamda * theta
        print times,theta
    return theta

这里是L1正则化,区别于规则方程

Arduino:串口的使用

	
int counter=0; // 计数器
 
void setup() {
// 初始化串口
  Serial.begin(9600);
}
 
void loop() {
// 每loop循环一次,计数器变量加1
counter = counter+1;
// 输出变量
Serial.print(counter);
// 输出字符
Serial.print( ':' );
// 输出字符串;
Serial.println("Hellow World");
delay(1000);
}

输出

void setup() {
  // 初始化串口
  Serial.begin(9600);
}
 
void loop() {
  // 读取输入的信息
  char ch=Serial.read();
  // 输出信息
  Serial.print(ch);
  delay(1000); 
}

 

I LOVE YOU (单片机)

#include<reg51.h>
#include<intrins.h>

sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;

#define COMMONPORTS		P0

unsigned char code TAB[8]  = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};

unsigned char code CHARCODE[4][8]=
{

{0x00,0x00,0xc3,0xff,0xff,0xc3,0x00,0x00},
{0x00,0x18,0x24,0x12,0x12,0x24,0x18,0x00},
{0x38,0x44,0x42,0x21,0x21,0x42,0x44,0x38},
{0x00,0xf0,0xf8,0x1f,0x1f,0xf8,0xf0,0x00}	

};
void delay(unsigned int time)
{
  unsigned int i,j;
  for(i=0;i<time;i++)
    for(j=0;j<121;j++);
}

void Hc595SendByte(unsigned char dat)
{
	unsigned char a;
	SRCLK=0;
	RCLK=0;
	for(a=0;a<8;a++)
	{
		SER=dat>>7;
		dat<<=1;

		SRCLK=1;
		_nop_();
		_nop_();
		SRCLK=0;	
	}

	RCLK=1;
	_nop_();
	_nop_();
	RCLK=0;
}


void main()
{	
 	unsigned char tab, j;
	unsigned int  i;

	while(1)
	{	
		for(i= 0; i<50; i++ ) 
		{
			for(tab=0;tab<8;tab++)
			{	

				Hc595SendByte(0x00);			    																
				COMMONPORTS	= TAB[tab];				 
				Hc595SendByte(CHARCODE[j][tab]);	
				delay(2);		
			}
			 
		}
		j++;
		if(j == 4)
		{
			j = 0;
		}
	}	
}

 

来自新世界:输入,输出和文件

金字塔输出hello

int main(){
  using namespace std;
  const char *p = "hello";
  int len = strlen(p);
  for (int i = ; i <= len;i++){
    cout.write(p, i);
    cout << endl;
  }
}

设置空格(只对下一个有效)

int main(){
  using namespace std;
  cout << "#";
  cout.width(12);
  cout << 12 << "#";
}

设置填充字符

int main(){
  using namespace std;
  //cout << "#";
  cout.fill('*');
  cout.width(12);
  cout << 12 << endl;
  cout.width(12);
  cout << 50 << endl;
}

显示全部数字

int main(){
  using namespace std;
  float p = 20.140;
  float p2 = 1.9 + 1.0 / 3.0;
  cout.setf(ios_base::showpoint);
  cout << p << endl;
  cout << p2 << endl;
}

 

来自新世界:标准模板库

什么是STL?

STL可分为容器(containers)、迭代器(iterators)、空间配置器(allocator)、配接器(adapters)、算法(algorithms)、仿函数(functors)六个部分

 

引入:模板类vector

vector<int> ratings(2);

这里建立了一个类型为int,名字是rating的vector类,这个rating里面有两个int元素(其实就是数组)

但是这个vector类对外有接口,比如begin()方法返一个指向容器中第一个元素的迭代器,迭代器是什么?它可以是指针,可对其执行类似指针的操作(解除引用,递增),它存在的意义就是让STL能够为各种各样不同的容器类提供统一的接口。迭代器的类型是一个名字为iterator的typedef,作用域为整个类。

int main(){
  vector<int>::iterator pd;
  vector<double> scores;
  pd = scores.begin();
  *pd = 55;
  pd++;

  auto pd = scores.begin();  //也可以通过auto直接声明使用
}

还有其他用法:

  vector<double> scores;
  double temp;
  while(cin >> temp){
    scores.push_back(temp);
  }
  cout << scores.size() << endl;
  scores.erase(scores.begin(), scores.begin() + 2);//删除第一个到第二个的元素
  scores.erase(scores.begin(), scores.end())       //end()返回末尾元素的后一个位置
  scores<int> new;
  scores.insert(scores.begin(), new.begin(), new.begin() + 5);

下面就来讲讲喜闻乐见的sort()函数,以前特别讨厌去写排序,一直想着去用sort去解决问题,那时都是用sort去对一个int/double数组进行排序,然鹅怎么对对象进行排序呢?

就是重载<,或者重新定义一个函数然后把函数当成参数传进sort()里面去

  bool operator<(const A &a1,const A &a2){
    if(a1.data > a2.data){
      return true;
    }
    else
      return false;
  }

  sort(book.begin(), book.end());

  bool Another(const A &a1,const A &a2){
    if(a1.data < a2.data){
      return true;
    }
    else
    {
      return false;
    }

    sort(book.begin(), book.end(), Another);

泛型编程

1.迭代器:连接容器和算法的一种重要桥梁,迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。

迭代器可以分为一下5种:

  • 输入迭代器:仅仅读。支持++、==、!=
  • 输出迭代器:仅仅写,支持++
  • 前向迭代器:读写,支持++、==、!=
  • 双向迭代器:读写,支持++、–
  • 随机訪问迭代器:读写,支持++、–、[n]、-n、<、<=、>、>=

 

前文提到像begin()方法,find()方法它也会返回一个迭代器,我们来看一下它的函数原型:

template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T &value);

 

 

这里声明了find方法要传进一个输入迭代器,

我们可以看出,find是一种算法,vector是一种容器里面可以塞任何东西,当需要把算法应用于容器时,我们为了控制,才使用迭代器这个东西,可以看出不同的迭代器有着不同的权限,这也要求我们要根据算法的需求来选择迭代器。比如查找算法只需要定义++运算符和读取数据(假如查找算法可以修改数据将会变得很蛋疼)

 

sort算法使用双向迭代器对vector里面的数据进行修改与排序

 

 

事实上,迭代器是广义上的指针,指向int的常规指针是一个随机访问迭代器模型。

  ostream_iterator<int, char> out_iter(cout, "\n");  //第一个参数是输出方式,第二个是分隔符
  int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  vector<int> dice(10);  
  copy(x, x + 10, dice.begin());   //复制函数
  copy(dice.begin(), dice.end(), out_iter);    //将dice容器中的内容复制到输入流中
  exit(5);

再来讲讲其他有用的迭代器

1.反向类迭代器,vector里面有一个rbegin和rend方法,返回的值分别和end与begin方法返回的值相同,但是前两者返回的迭代器的类型是reverse_iterator而不是iterator

2.插入迭代器(预定义的),在通过copy来把数据插到容器中时,很有可能会覆盖掉前面的数据,那么这时就要把特殊的迭代器传进容器中了

copy(dice.begin(), dice.end(), back_insert_iterator< vector<int> > (words)); //将dice里面的内容从后面复制到words中

 

顺带一提copy可以:

  1. 将信息从一个容器复制到另外一个容器中
  2. 把数据从容器中复制到输出流
  3. 把信息从一个容器中插入到另外一个容器中

我们再来回顾一下前面的那一张图,我们可以发现,copy作为一种独立的算法,通过传给它不同的迭代器,可以实现对不同种类的容器的不同操作(输出,复制,插入)。

 

2.容器

list vector 什么的,还有关联容器set map pair,看的脑子疼就不计下来了

那个map和pair可以搭配使用

// multmap.cpp -- use a multimap
#include <iostream>
#include <string>
#include <map>
#include <algorithm>

typedef int KeyType;
typedef std::pair<const KeyType, std::string> Pair;
typedef std::multimap<KeyType, std::string> MapCode;

int main()
{
    using namespace std;
    MapCode codes;

    codes.insert(Pair(415, "San Francisco"));
    codes.insert(Pair(510, "Oakland"));
    codes.insert(Pair(718, "Brooklyn"));
    codes.insert(Pair(718, "Staten Island"));
    codes.insert(Pair(415, "San Rafael"));
    codes.insert(Pair(510, "Berkeley"));

    cout << "Number of cities with area code 415: "
         << codes.count(415) << endl;
    cout << "Number of cities with area code 718: "
         << codes.count(718) << endl;
    cout << "Number of cities with area code 510: "
         << codes.count(510) << endl;
    cout << "Area Code   City\n";
    MapCode::iterator it;
    for (it = codes.begin(); it != codes.end(); ++it)
        cout << "    " << (*it).first << "     "
            << (*it).second    << endl;

    pair<MapCode::iterator, MapCode::iterator> 
		auto range
         = codes.equal_range(718);
    cout << "Cities with area code 718:\n";
    for (it = range.first; it != range.second; ++it)
        cout <<  (*it).second    << endl;
    // cin.get();
    return 0; 
}

我感觉有点用的核心语句:

//利用map可以像数组那样子通过[]来访问数据来统计单词
map<string, int> wordmap;
set<string>::iterator si;
for (si = word.begin(); si != word.end();si++)  //si指向单词
     wordmap[*si] = cout(word.begin(), word.end(), *si);

 

函数对象

函数对象是可以以函数方式与()结合使用的任意对象,包括:

1)函数名;

2)指向函数的指针;

3)重载了()操作符的类对象(即定义了函数operator()的类)

那又何必有所谓的仿函数呢?原因在于函数指针毕竟不能满足STL对抽象性的要求,也不能满足软件积木的要求——函数指针无法和STL其他组件(如配接器adapter)搭配,产生更灵活的变化。同时,函数指针无法保存信息,而仿函数可以。

 

。。。

 

看不懂,可能是直接用函数对象比较方便吧,比如:
template <class T,class S>   
  void fun(T &a,S &b){
    cout << a << ' ' << b << endl;
  }
//template void fun<int, double>(int &a, double &b);
int main(){
  
  int a = 1;
  double b = 2.5;
  string c = "hello";

  fun(a, b);
  void (*p1)(int &a, string &c) = fun;    //函数指针版本
  p1(a, c);

}
void show(const int a){
  cout << a << endl;
}
int main(){
  ostream_iterator<int, char> out_iter(cout, "\n");  //第一个参数是输出方式,第二个是分隔符
  int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  vector<int> dice(10);  
  copy(x, x + 10, dice.begin());   //复制函数
  for_each(dice.begin(), dice.end(), show);    //直接传函数版本
}
template <class T>
class show{
  public:
    show(){}
    void operator()(T &i) { cout << i << endl; }
};
int main(){
  ostream_iterator<int, char> out_iter(cout, "\n");  //第一个参数是输出方式,第二个是分隔符
  int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  vector<int> dice(10);  
  copy(x, x + 10, dice.begin());   //复制函数
  for_each(dice.begin(), dice.end(), show<int>());  //使用函数对象
}

 

这里可以发现,要用函数指针,先要这样子写一大串东西,然后才能传进去,但是用类的话会方便一点,直接实例化A<int>/<double>/<string>就完事了,然后还可以保存信息什么的,扩展性很高,但是占用内存更大和效率会比函数指针要慢得多。

 

其他库

1.vector,valarray,array

2.模板initializer_list:就是可以使用初始化列表语法来初始化STL容器,因为容器类现在包含将initializer_list<T>作为参数的构造函数。例如vector<double>包含一个将initializer_list<double>

作为参数的构造函数。

vector<int> x {1, 2, 3, 4, 5};

数据可以进行有必要的转化但不能隐式的窄化转化

 

总结

STL是一个容器类模板,迭代器模板,函数对象模板和算法模板的集合,他们的设计都是基于泛编程原则的。

  • 诸如vector和set等容器类是容器的概念(容器,序列,关联容器)的模型
  • 有一些算法被表示为容器的类方法,但是大量算法都被表示为通用的,非成员函数的,这是通过将迭代器作为容器和算法之间的接口得以实现的(把迭代器(这个类)给传进去,比如要把数据复制到输出流就传一个ostream_iterator,这样就把数据复制到输出流中。比如只是单纯的复制的话就传一个输入迭代器就成)。还有一个优点就是,我们只需要一个诸如copy(),for_each()这样的函数就可以了而不需要为每一个容器提供不同的版本。另外一个优点就是STL算法可以用于非STL容器,如常规数组,string对象。
  • 上面可以看到,算法对容器是有要求的,容器必须支持算法所需的迭代器,不然就要提供一个专门的方法。
  • STL还提供了函数对象,函数对象是重载了()运算符的类,可以用函数的表示方法来调用这种类的对象,同时可以携带更多的信息。

来自新世界:智能指针

不会发生内存泄漏的东西

智能指针的三个模板:auto_ptr  unique_ptr shared_ptr

当智能指针过期时,其析构函数会自动调用delete来释放内存。

void remodel(std::string& str){
  std::auto_ptr<std::string> ps(new std::string(str));
  *ps = str;
  cout << *ps;
  return;
}

注意所有指针都有一个explicit的构造函数,因此不能这样做:

shared_ptr<double> pd;
double *p_reg = new double;
//pd = p_reg;   不允许,需要显示转换
pd = shared_ptr<double>(p_reg);

事实上,我们可以发现,在编译文件时,vs code会发出警告,那是因为C++11已经要抛弃这个auto_ptr了。

为啥呢?

这个是因为有一个东西叫所有权,当一个智能指针赋值给了另外一个时,原来的就会放弃它的所有权,因此再次用原来的智能指针访问数据时就会出错。(我们称为“悬挂指针”)

void remodel(std::string& str){
  std::auto_ptr<std::string> ps(new std::string(str));
  *ps = str;
  auto_ptr<string> pt = ps;
  cout << *pt;
  cout << *ps;   //这时系统会卡住
  return;  
}

怎么办?

可以把auto_ptr换成shared_ptr或者unique_ptr,前者的机制是当有多个指针指向同一对象时,引用计数增加,在析构时(先析构)那个最后声明的指针,其析构函数把计数器数减一,直到计数器降低到0时才会释放分配的空间。后者的机制是在使用等于号那一步编译器就报错了。但其实也不是不能通过等于号来给unique_ptr指针赋值,如果给它赋值的是临时右值,就不会报错,因为反正这个右值它很快就会被销毁了。

unique_ptr<string> demo(const char*s){
  unique_ptr<string> temp(new string(s));
  return temp;
}

unique_ptr<string> ps;
ps = demo("Uniquely special");   //编译器不会报错

事实上也可以单纯的用等号,右值也不用是临时变量,在要转移的指针上加个move方法就行

怎么选择智能指针

如果有多个指针指向同一个元素,比如有很多个对象,但是每个对象里面都有两个指针,指向某个最大值和最小值,这时就要用shared_ptr

来自新世纪:打开文件

#include <iostream>
#include <string.h>
#include <fstream>
using namespace std;
int main(){
  ifstream fin;
  fin.open("a.txt");
  if(fin.is_open()==false){
    cerr << "can't open file\n";
    exit(EXIT_FAILURE);
  }
  string item;
  int count = 0;
  getline(fin, item, ':');
  while(fin){
    ++count;
    cout << count << ":" << item << endl;
    getline(fin, item, ':');
  }
  cout << "Done" << endl;
  fin.close();
  return 0;
}

 

来自新世界:RTTI和类型转换运算符

RTTI元素

  • dynamic_cast 运算符将使用一个指向基类的指针来生成一个指向派生类的指针。否则返回一个空指针。
  • typeid 运算符返回一个指出对象的类型的值
  • type_info 结构储存了有关特定类型的信息

上代码:

#include <iostream>
using namespace std;
class A{
    private:
      int i;
    public:
    A(int j):i(j){}
    virtual void show(){
        cout << "this is A:" << i << endl;
    }
};
class B:public A{
    private:
      int k;
    public:
    B(int o,int p):A(o),k(p){}
    void show(){
        cout << "this is B:" << k << endl;
    }
    void hello(){
        cout << "fuck" << endl;
    }

};
int main(){
    A *p = new B(5,1000);
    B *pai = new B(100,66);
    /*if(p = dynamic_cast<B*>(pai))  //利用派生类指针生成派生类指针赋给基类指针
    {
        p->show();
        cout << "successful" << endl;
    }*/
    if(pai = dynamic_cast<B*>(p))  //利用基类指针生成派生类指针赋给派生类类指针
    {
        pai->show();
        cout << "successful" << endl;
    }
    
}

结果是:

 

dynamic_cast在将父类cast到子类时,父类必须要有虚函数!!

具体有什么用呢?

其实就是基类指针可以指向它的派生类,但是有时候通过基类指针会调用到基类没用的方法,这时我们就可以用这个转换去通过使用一个基类指针来生成一个派生类指针再赋给其他指针,从而进行灵活的运用而不是通过typeid 和 if else 来判断这个基类指针指向的到底是什么类,再把操作写进去

类型转换运算符

上面说的dynamic_cast就是一种,而其他的还有像const_cast可以通过指针改变被const指针指向的值:

High bar;
const High *p_bar = &bar;
High *pb const_cast<High *>(p_bar); //这样使得 pb 可以修改 bar 指向的对象

但是如果对象本来就是const,那终究是修改不了的。

来自新世界:关于子类父类的同名函数

之前我一直以为若子类的公有函数要和父类同名只能加个virtual,事实上不是的:

#include <iostream>
using namespace std;
class A{
    private:
      int i;
    public:
    A(int j):i(j){}
    void show(){
        cout << "this is A:" << i << endl;
    }
};
class B:public A{
    private:
      int k;
    public:
    B(int o,int p):A(o),k(p){}
    void show(){
        cout << "this is B:" << k << endl;
    }
    void hello(){
        cout << "fuck" << endl;
    }

};
int main(){
    A y(5);
    B x(5,5); 
    A *p = &x;   //派生类指针不能指向基类
    //y.show();
    //x.A::show();
    p->show();   //加了virtual就调用派生类(B)的show函数
    ((B *)p)->show();
}

 

 

这时我们可以发现,即使基类指针指向派生类,调用的依旧是父类的函数,而非像加了virtual那样子的调用子类版本的show(),但是当指针被强制转换为子类指针时才可以调用子类的函数。想要用基类指针调用不同的版本的函数,就要在父类的show()前加一个virtual。

然鹅我突然想到,为什么这两个show函数不会冲突呢?其实这两个函数不在同一个作用域里面,C++会先去子类中搜索要用的函数,找不到再去父类里面找,因此如果要在子类对象里面调用父类函数,可以在子类对象中使用解析符 :: 去调用基类方法。

int main(){
    A y(5);
    B x(5,5); //派生类指针不能指向基类
    A *p = &x;
    y.show();
    x.A::show();
}

最后来个汇总:

#include <iostream>
using namespace std;
class A{
    private:
      int i;
    public:
    A(int j):i(j){}
    void show(){
        cout << "this is A:" << i << endl;
    }
};
class B:public A{
    private:
      int k;
    public:
    B(int o,int p):A(o),k(p){}
    void show(){
        cout << "this is B:" << k << endl;
    }
    void hello(){
        cout << "fuck" << endl;
    }

};
int main(){
    A x(5);
    B y(5,5);
    //B *pt = &x;   派生类指针不能指向基类
    A *pi = &x;
    B *p = &y;
    pi->show();
    ((B *)pi)->show();   //将基类指针强制转换为派生类指针
    ((B *)pi)->hello();
    //p = &x;      报错,派生类不可以指向基类
    p->hello();
    p->show();
    ((A *)p)->show();       //将派生类指针强制转换为基类指针
    //y.show();
    //x.A::show();
}

结果:

 

 

(第二个由于没有默认构造一个B类,也就是没用构造好B类的部分,因此B类的私有成员值会变成一串无意义的数字)