Страницы

Поиск по вопросам

вторник, 24 декабря 2019 г.

Что означает “?” в дженериках?

#java #классы #рефлексия


Изучаю сейчас Reflection. В примере есть строка

Class cls1 = Integer.class;


Что означает знак вопроса?
И почему нельзя просто написать 

Class cls1 = Integer.class;

    


Ответы

Ответ 1



Grundy прав. По идее он может быть полезен в трех случаях. Когда классов обобщения несколько и лишь один нужно оставить неизвестным. Когда вам необходимо одну и ту же переменную инициализировать объектами с разными видами обобщения. Если использовать Object то при инициализации new List будет ошибка, а при вы сможете инициализировать эту переменную и как new List и как new List. Исходя из предыдущего, вы можете определять ее каким-либо интерфейсом или суперклассом , и инициализировать любым классом, который подходит этим критериям, а не только конкретно этим интерфейсом или классом (Этакая двойная фильтрация).

Зависает “Подготовка к установке Ubuntu”

#ubuntu


На компьютере уже стоит винда 8 и убунту, но последняя в не рабочем состоянии (подробности
о неработоспособности можно посмотреть в моем прошлом вопросе), загрузился с флешки,
копировал /home директорию на раздел с данными, пробую переустановить убунту, но она
зависает на моменте "Подготовка к установке Ubuntu", так же всплывает непонятный алерт.



Что не так? Как это пофиксить?

Так же интересует не убьется ли уже существующий grub, в котором есть пункт загрузки
винды при переустановке убунты?

P.S. С ubuntu ковыряюсь 4 день, ответ хотелось бы получить максимально развернутый.
Если надо куда-то залезть и посмотреть какие-то логи, пожалуйста, напишите как залезть
и т.п. Заранее спасибо!
    


Ответы

Ответ 1



Попробуй перезаписать установочную флешку. UNetbootin в помощь!

Зачем в JavaScript использовать паттерн singleton?

#javascript #ооп #шаблоны_проектирования


Разбираюсь с паттернами. Нашёл в интернете, как сделать на JavaScript конструктор,
который бы реализовывал паттерн singleton. Но ведь, как я понимаю, в отличие от многих
ООП языков, в JavaScript можно создавать объекты, не описывая классы (конструкторы),
а просто создать через фигурные скобочки. Получается, можно всегда, когда в JavaScript
нужен singleton, писать не конструктор его реализующий, а просто создавать глобальный
объект, и пользоваться им, присваивая его другим переменным. Подскажите, пожалуйста,
есть ли в этом недостатки в сравнении с созданием конструктора, реализующего singleton?
    


Ответы

Ответ 1



Формально, эти самые 'фигурные скобочки' тоже создаются через конструктор new Object, как и примитивы через обёртки. В пространстве JS, где всё непостоянно и специфично (во всяком случае было когда-то), этот паттерн не очень-то нужен. Сейчас, когда JS вырос из песочницы браузеров и занимает внушительную нишу, он может использовать Singleton для взрослых целей, где после инициализации менять ничего не нужно: одно подключение к БД, один объект пользователя/сессии и пр. Впрочем, с новыми возможностями (Object.seal, Object.preventExtensions, Object.freeze), этот паттерн опять же не нужен - всё решено изящнее и в духе языка (ИМХО).

C++ при записи структуры в файл с помощью fwrite в файле отображаются крякозябры

#cpp


Делаю лабу в универе. Есть структуры, данные которых вводятся с клавиатуры, потом
записываются в файл с помощью функции fwrite(). До сих пор работал только с fstream,
и проблем не возникало. Тут тоже вроде как всё сделал правильно, но на выхлопе получаю
файл device.txt, а в нём сплошные крякозябры. Собираю с под линукса g++. 
Вся программа на гите https://github.com/rotenbergwitalik/laba6.git

код с main:

#include 
#include 

#define DEVICE_NAME_LEN     30
#define MEASUREVALUE_NAME_LEN     30

using namespace std;

struct powerSource {
    float voltage;
    float amperage;
    float periodicity;
};

struct measuredValue {
    char measuredValueName[MEASUREVALUE_NAME_LEN];
    float lowBorder;
    float highBorder;
    float inaccuracy;
};

struct device {
    char deviceName[DEVICE_NAME_LEN];//
    float devicePrice;
    int guarantee; //in month
    struct powerSource devicePowerSource;
    struct measuredValue deviceMeasureValue;
};
int main() {
    struct device labaDevice;

    cout<<"Write name of device: ";
    cin>>labaDevice.deviceName;
    cout<<"Write price of device in $: ";
    cin>>labaDevice.devicePrice;
    cout<<"Write guarantee in month: ";
    cin>>labaDevice.guarantee;

    cout<<"Write power source for device: "<>labaDevice.devicePowerSource.voltage;
    cout<<"\tAmperage: ";
    cin>>labaDevice.devicePowerSource.amperage;
    cout<<"\tPeriodicity: ";
    cin>>labaDevice.devicePowerSource.periodicity;

    cout<<"Write measure value for device: "<>labaDevice.deviceMeasureValue.measuredValueName;
    cout<<"\tLow border: ";
    cin>>labaDevice.deviceMeasureValue.lowBorder;
    cout<<"\tHigh border: ";
    cin>>labaDevice.deviceMeasureValue.highBorder;
    cout<<"\tInaccuracy: ";
    cin>>labaDevice.deviceMeasureValue.inaccuracy;

    FILE* outFile;
    if ((outFile = fopen("device.txt", "wb")) == NULL) {
        cout<<"Con not open the file"<


Ответы

Ответ 1



Думаю, что вы просто раньше выводили поля с помощью оператора вывода в поток <<, т.е. в текстовом виде. fwrite пишет данные в бинарном виде, как есть. Режим wt меняет одно - обработку \n. Если вы хотите получать все данные в текстовом виде, используйте fprintf - типа, вместо outStream << "guarantee = " << labaDevice.guarantee << endl; используйте fprintf(outFile,"guarantee = %d\n",labaDevice.guarantee); Но учтите, что если потом надо будет считывать - то считывать тоже надо будет текстово. А если используете fwrite в бинарном режиме - то потом всю структуру сразу втянете одним fread в том же бинарном режиме...

Ответ 2



"Кракозябры" зависят от того просмотрщика, которым ты этот файл смотришь. Большинство из них пытаются определить кодировку автоматом. Но т. к. файл записывается не текстовый а бинарный, то вполне возможны ошибки. Если под linux, то из консоли можно посмотреть тем же mc F3. После открытия Alt+E и выбираешь ту, которая у тебя стоит - utf-8, например. Да, и лучше переключится в HEX - режим, чтобы просмотрщик не пытался интерпретировать значения из float или int как текст. :) Кстати, имей в виду, что если кодировка у тебя utf-8 и ты используешь не ascii символы, например русские, то длинна строки в байтах может увеличится раза в 3. Так что при вводе имени из 10-15 символов можешь затереть остальные поля структуры мусором или схватить переполнение стека. :)

Ответ 3



Следует исправить строчку (открытие файла в бинарном режиме) if ((outFile = fopen("device.txt", "wb")) == NULL) { на строчку: if ((outFile = fopen("device.txt", "wt")) == NULL) { После этого надо вручную выводить все поля структуры примерно вот так: fwrite("labaDevice.deviceName = ", sizeof("labaDevice.deviceName = "), 1, outFile); fwrite(labaDevice.deviceName, sizeof(labaDevice.deviceName), 1, outFile);

SimpleCursorAdapter + ListView: Чекбоксы теряются при скроллинге

#android #listview #checkbox


Чекбоксы при уходе за экран, теряют свои положения при возвращении. Вот тут - SimpleCursorAdapter
- фильтр для курсора
есть весь код (мой вопрос). Как реализовать метод для сохранения булевых значений?
Неужели вместо курсора в адаптер мне нужно отправлять массив булевых значений? А как
взятие данных через курсор в методе bindView()? Ведь курсор я уберу, а он нужен.

Mетод для получения данных с БД

private void getProductList()
{
    String filter = "list=" + intValue;
    final Cursor cursor = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID,
        DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT,
DatabaseProductHelper.PRODUCT_LIST, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}, 
        null, null,  null, null, null) ;  
    final Cursor cursorc = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID,
                                                    DatabaseProductHelper.PRODUCT_NAME,
DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_LIST, DatabaseProductHelper.PRODUCT_TYPE,
DatabaseProductHelper.PRODUCT_COMPLETE}, 
                                                filter, null,  null, null, null) ;
    final ArrayList arrTblNames = new ArrayList();

    if (cursor.moveToFirst()) {
        while ( !cursor.isAfterLast() ) {
            if(cursor.getInt(cursor.getColumnIndex("list"))==intValue)
            {
            arrTblNames.add(cursor.getString(cursor.getColumnIndex("name")));
            }
            cursor.moveToNext();
            }

        String[] from = {DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT,
DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE};
        int[] to = {R.id.ColMemberID, R.id.ColName, R.id.count_tv, R.id.chb_products};
        adapter = new InteractiveArrayAdapter(ListBuilder.this,
        R.layout.row,
        cursorc,
        from,
        to
        );
        //lv_products.setAdapter(adapter);

    }



    if(!arrTblNames.isEmpty()){
        empty_bd_layout.setAlpha(0);
        lv_products.setAdapter(adapter);
    }
    else{
empty_bd_layout.setAlpha(255);
}
}


И сам адаптер

public class InteractiveArrayAdapter extends SimpleCursorAdapter
{
    private int layout;
    private boolean checked[];
    public InteractiveArrayAdapter(Context _context, int _layout, Cursor _cursor,
String[] _from, int[] _to) {
        super(_context, _layout, _cursor, _from, _to);
        layout = _layout;
        int counts = _cursor.getCount();
        checked = new boolean[counts];

                for (int i = 0; i < counts; i++){

                    int checkMarker = _cursor.getInt(_cursor.getColumnIndex("complete"));
                    checked[i] = checkMarker == 1;
            }


    }

    @Override
    public void bindView(View view, Context _context, Cursor _cursor) {




        String prod_name = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_NAME));
        String prod_count = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COUNT));
        String prod_type = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_TYPE));
    //  int prod_complete = _cursor.getInt(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COMPLETE));
        TextView name_prod_tv = (TextView)view.findViewById(R.id.ColMemberID);
        TextView count_prod_tv = (TextView)view.findViewById(R.id.ColName);
        TextView type_prod_tv = (TextView)view.findViewById(R.id.count_tv);
        CheckBox chb = (CheckBox)view.findViewById(R.id.chb_products);

        chb.setFocusable(false);

        chb.setClickable(false);

        name_prod_tv.setText(prod_name);

        count_prod_tv.setText(prod_count);

        type_prod_tv.setText(prod_type);

        chb.setChecked(checked[_cursor.getPosition()]);

        }
    @Override
    public View newView(Context _context, Cursor _cursor, ViewGroup _parent)
    {
        LayoutInflater inflater = (LayoutInflater)_context.getSystemService(_context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(layout, _parent, false);
        return view;
    }
    public void setChecked(int position){
        // инвертируем значение при обработке клика этим методом
        checked[position]=!checked[position];
    }
}


LogCat
FATAL EXCEPTION: main
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               Process:
ru.diskrim.listbuy, PID: 1468
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               java.lang.RuntimeException:
Unable to start activity ComponentInfo{ru.diskrim.listbuy/ru.diskrim.listbuy.ListBuilder}:
android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 4
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.access$800(ActivityThread.java:151)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.os.Handler.dispatchMessage(Handler.java:102)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.os.Looper.loop(Looper.java:135)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.main(ActivityThread.java:5254)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
java.lang.reflect.Method.invoke(Native Method)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
java.lang.reflect.Method.invoke(Method.java:372)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
de.robv.android.xposed.XposedBridge.main(XposedBridge.java:117)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               Caused
by: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 4
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.database.AbstractCursor.checkPosition(AbstractCursor.java:426)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:68)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
ru.diskrim.listbuy.ListBuilder$InteractiveArrayAdapter.(ListBuilder.java:245)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
ru.diskrim.listbuy.ListBuilder.getProductList(ListBuilder.java:209)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
ru.diskrim.listbuy.ListBuilder.onCreate(ListBuilder.java:184)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.Activity.performCreate(Activity.java:6033)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
05-09 07:18:29.529 1468 1468 E     AndroidRuntime                               ...
11 more
    


Ответы

Ответ 1



Решение мало чем отличается от этого ответа, с той разницей, что вам нужно обрабатывать клики из активити, а не слушателем в адаптере. Поскольку мы не можем изменять значения в курсоре, а только читать их оттуда, для запоминания текущего состояния чекбоксов требуется создать локальное хранилище. В адаптер вам нужно передавать данные, которые должны быть отображены в виджете, в вашем случае это курсор с выборкой из БД. Вспомогательный массив булевых значений никуда передавать не нужно, он создается внутри адаптера. Примерная реализация может выглядеть так: private void getProductList() { // Если требуется только имя, следует и запрашивать из БД только //колонку с именем, а не все в кучу // Если требуется только записи с каким то условием, то их и надо запрашивать, // а не все в подряд, а потом выбирать нужные каким то циклом // так же эти данные включены и в курсор для адаптера и нет нужды // получать то же самое дважды // final Cursor cursor = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID, DatabaseProductHelper.PRODUCT_NAME,"list = ?", new String[] {""+ intValue}, null, null, null) ; //то же самое, только нужные в адаптере колонки final Cursor cursorc = mSqLiteDatabase.query("products", new String[] {DatabaseProductHelper.PRODUCT_ID,DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}, "list = ?", new String[] {""+ intValue}, null, null, null); final ArrayList arrTblNames = new ArrayList(); // копирование данных из курсора в массив сильно упрощается, // так как у нас только нужные данные while ( cursorc.moveToNext() ) { arrTblNames.add(cursorc.getString(cursorc.getColumnIndex("name"))); } String[] from = {DatabaseProductHelper.PRODUCT_NAME, DatabaseProductHelper.PRODUCT_COUNT, DatabaseProductHelper.PRODUCT_TYPE, DatabaseProductHelper.PRODUCT_COMPLETE}; int[] to = {R.id.ColMemberID, R.id.ColName, R.id.count_tv, R.id.chb_products}; adapter = new InteractiveArrayAdapter(ListBuilder.this, R.layout.row, cursorc, from, to ); //lv_products.setAdapter(adapter); } // у виджетов есть свойство Visiblity, которое управляет видимостью на // экране, зачем тут использовать прозрачность ? // я бы поменял всю логику вообще, исходя из условия ниже, // зачем получаnь и формировать данные, если они могут не понадобится if(!arrTblNames.isEmpty()){ empty_bd_layout.setAlpha(0); lv_products.setAdapter(adapter); } else{ empty_bd_layout.setAlpha(255); } } адаптер: public class InteractiveArrayAdapter extends SimpleCursorAdapter { private int layout; private boolean checked[]; public InteractiveArrayAdapter(Context _context, int _layout, Cursor _cursor, String[] _from, int[] _to) { super(_context, _layout, _cursor, _from, _to); layout = _layout; // инициализируем вспомогательный массив начальными отметками чекбоксов из курсора checked = new boolean[_cursor.getCount()]; int i = 0; while ( _cursor.moveToNext() ) { int checkMarker = _cursor.getInt(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COMPLETE)); checked[i] = (checkMarker == 1) ? true: false; i = i + 1; } // нужно вернуть указатель курсора в первоначальное положение // перед первой записью, для корректной работы адаптера _cursor.moveToPosition(-1); } @Override public void bindView(View view, Context _context, Cursor _cursor) { String prod_name = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_NAME)); String prod_count = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COUNT)); String prod_type = _cursor.getString(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_TYPE)); // эта строка здесь теперь по видимому не нужна, поскольку значения отметок // из курсора мы уже извлекли //int prod_complete = _cursor.getInt(_cursor.getColumnIndex(DatabaseProductHelper.PRODUCT_COMPLETE)); TextView name_prod_tv = (TextView)view.findViewById(R.id.ColMemberID); TextView count_prod_tv = (TextView)view.findViewById(R.id.ColName); TextView type_prod_tv = (TextView)view.findViewById(R.id.count_tv); CheckBox chb = (CheckBox)view.findViewById(R.id.chb_products); chb.setFocusable(false); chb.setClickable(false); name_prod_tv.setText(prod_name); count_prod_tv.setText(prod_count); type_prod_tv.setText(prod_type); // устанавливаем чекбоксы по вспомогательному массиву, а не по курсору // получаем текущую позицию курсора (и соответственно адаптера) через его метод chb.setChecked(checked[_cursor.getPosition()]); } @Override public View newView(Context _context, Cursor _cursor, ViewGroup _parent) { LayoutInflater inflater = (LayoutInflater)_context.getSystemService(_context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(layout, _parent, false); return view; } // метод для фиксации изменений отметок чекбоксов из активити public void setChecked(int position){ // инвертируем значение при обработке клика этим методом checked[position] = !checked[position]; } } запись изменений в БД по отметкам чекбоксов у вас, насколько я помню, осуществляется при обработке клика в слушателе списка, поэтому в адаптер это действие не включено, но оно должно обязательно присутствовать, иначе при выходе из списка отметки будут утеряны.

Yii2 и Яндекс Касса

#php #yii2 #яндекс


Три часа борюсь с яндекс кассой. Саппорт говорит  что у меня сайт не принимает POST
запросы и возвращает bad request #400. Сайт на Yii2. Есть предположение что это из
за ckrf токена. Может быть кто то сталкивался и сможет мне помочь?
    


Ответы

Ответ 1



В контроллере реализуйте метод beforeAction таким образом. public function beforeAction($action) { $this->enableCsrfValidation = false; return parent::beforeAction($action); } Если не хотите отключать CSRF для всех действий, то можете отключить для определенных действий: public function beforeAction($action) { if ($action->id === 'test') $this->enableCsrfValidation = false; return parent::beforeAction($action); } В данном случае мы отключили CSRF для действия test

Ответ 2



Для нескольких экшенов: public function beforeAction($action) { $this->enableCsrfValidation = !in_array($action->id, ['check', 'aviso']); return parent::beforeAction($action); }

JavaFX 8 3D : провести Cylinder от точки А до точки B, заданных Point3D объектами

#java #javafx #3d


Возникла необходимость соединить две точки цилиндром.
Есть координаты двух точек, заданных, как экземпляры Point3D:

Point3D pointA = new Point3D(100,200,150);
Point3D pointB = new Point3D(200,150,-100);


Есть группа (javafx.scene.Group), в которой производятся построения:

Group space3D = new Group();


Задача: соединить эти две виртуальные точки (можно разместить в этих координатах
по экземпляру Sphere радиусом 10, для наглядности) экземпляром javafx.scene.shape.Cylinder
радиусом 2, высотой равной расстоянию от точки А до точки B с минимальным количеством
действий.

П.С.: Какие альтернативы были бы более эффективными для визуального соединения двух
точек в 3D пространстве?
    


Ответы

Ответ 1



Начну от обратного.Пример решения: public Cylinder paintCylinder(Point3D A, Point3D B) { Point3D temp = A.subtract(B); double Y = temp.getX() != 0 || temp.getZ() != 0 ? B.getY() : B.getY() > A.getY() ? B.getY() : A.getY(); Point3D dir = A.subtract(B).crossProduct(new Point3D(0, -1, 0)); double angle = Math.acos(A.subtract(B).normalize().dotProduct(new Point3D(0, -1, 0))); double h1 = A.distance(B); Cylinder c = new Cylinder(2d, h1); c.getTransforms().addAll(new Translate(B.getX(), Y - h1 / 2d, B.getZ()), new Rotate(-Math.toDegrees(angle), 0d, h1 / 2d, 0d, new Point3D(dir.getX(), -dir.getY(), dir.getZ()))); return c; } Как результат: : теперь ближе к конкретным вопросам: Так сложилось что легче для понимания процедуры вращения объекта это последовательное вращение по 3 координатам (и применяется такой подход часто) Но если разобраться то вполне естественный ход поворачивать объект всего один раз на один конкретный угол.И если быть совсем точным поворачивают систему координат дабы на одной плоскости оказались точки начала и конца дуги поворота. Возможна также работа с матрицей поворота и как пример работы с ней данный ответ.Да конечно такой подход быстрее чем работа с последовательным поворотом по трем осям но хочу заметить что сам автор ответа(он же к слову и разработчик библиотеки - FXyz) по моим наблюдениям конкретно матричной реализацией не пользуется (наблюдение рамках открытого кода на GitHub).